C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[9]: フルパス付きでないファイル名(重複ファイルを考慮)


(過去ログ 169 を表示中)

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■97368 / inTopicNo.1)  フルパス付きでないファイル名(重複ファイルを考慮)
  
□投稿者/ KonNo (1回)-(2021/04/30(Fri) 12:28:50)

分類:[C#] 

下記は、ネットで見つけたC#のコードです。
  階層の深いディレクトリーにある複数のファイルを現在のディレクトリーに一括して
  移動させるコードです。

コードでは、階層を考慮してフルパス付きでファイル名が変更されますが
 これをファイル名だけにしたいのです。

1_2_3_4_test.txt ------> test.txt

但し、同名ファイルが複数ある場合は、ファイル名の最後に「_2」のように番号を追加したいです。

test.txt -----> test_2.txt や test_3.txt
  
C#に関しては、ド素人なのでコードを訂正いただけると嬉しいです。


-------------------------------
using System.IO;

namespace ZapAll
{
class Program
{
private static readonly char separator = Path.DirectorySeparatorChar;

static void Main(string[] args)
{
foreach (var item in Directory.EnumerateDirectories(Directory.GetCurrentDirectory()))
{
Zap(item);
}
}

static void Zap(string path)
{
// process children directories first
foreach (var dir in Directory.EnumerateDirectories(path))
{
Zap(dir);
}

// zap all files
foreach (var oldPath in Directory.EnumerateFiles(path))
{
var newPath = oldPath.Insert(oldPath.LastIndexOf(separator), "_");
newPath = newPath.Remove(newPath.LastIndexOf(separator), 1);

File.Move(oldPath, newPath);
}

// delete directory
Directory.Delete(path);
}
}
}
引用返信 編集キー/
■97374 / inTopicNo.2)  Re[1]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ ぶなっぷ (272回)-(2021/04/30(Fri) 14:03:42)
2021/04/30(Fri) 14:04:00 編集(投稿者)
こんな感じでどうでしょう。

var TgtDir = Directory.GetCurrentDirectory();
var tgtFiles = new Dictionary<string, FileInfo>();
var allFiles = Directory.EnumerateFiles(TgtDir, "*", SearchOption.AllDirectories).Select(x => new FileInfo(x));
var allFileGrps = allFiles.ToLookup(x => x.Name);
foreach (var files in allFileGrps)
{
    int index = 0;
    foreach(var file in files)
    {
        var fname = file.Name;
        if (index++ > 0)
        {
            var fname_head = fname.Substring(0, fname.Length - file.Extension.Length);
            fname = string.Format("{0}_{1}.{2}", fname_head, index, file.Extension);
        }
        tgtFiles.Add(fname, file);
    }
}
foreach (var tgtFile in tgtFiles)
{
    File.Move(tgtFile.Value.FullName, TgtDir + tgtFile.Key);
}
var allDirs = Directory.EnumerateDirectories(TgtDir, "*", SearchOption.AllDirectories);
foreach(var dir in allDirs.Reverse())
{
    Directory.Delete(dir);
}

EnumerateDirectories(), EnumerateFiles() は SearchOption.AllDirectories でフォルダ下
まとめて取得です。
あと、ToLookup()がミソです。
  https://mk.hatenablog.jp/entry/20090729/1248834368

引用返信 編集キー/
■97375 / inTopicNo.3)  Re[2]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ KonNo (2回)-(2021/04/30(Fri) 14:44:48)
ぶなっぷさん、
 コードの修正ありがとうございます。

ド素人の私は、無料のvisual Studio 2019 (v.16.9.4) でコンパイルしましたが、
以下のエラーが発生してしまいます。

c#9.0以上の言語バージョンが必要との事ですが
  どうすれば良いでしょうか ?



ビルドを開始しました...
1>------ ビルド開始: プロジェクト: ConsoleApp2, 構成: Release Any CPU ------
1>C:\Users\konno\source\repos\ConsoleApp2\ConsoleApp2\Program.cs(1,1,1,46): error CS8370: 機能 'トップレベルのステートメント' は C# 7.3 では使用できません。9.0 以上の言語バージョンをお使いください。
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

引用返信 編集キー/
■97376 / inTopicNo.4)  Re[3]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ ぶなっぷ (273回)-(2021/04/30(Fri) 15:03:06)
「C#9.0」どころか、「C#5.0」で作成したコードですよ。
コード、どこに貼ってますかぁ?

Main()メソッドの中に貼ってくださいね。
あと、必要な using とかもちゃんと追加してくださいね。

万が一、この意味が分からない場合は、さすがに、もう少し勉強されることをお勧めします。

引用返信 編集キー/
■97377 / inTopicNo.5)  Re[4]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ KonNo (3回)-(2021/04/30(Fri) 15:37:22)
No97376 (ぶなっぷ さん) に返信
> 「C#9.0」どころか、「C#5.0」で作成したコードですよ。
> コード、どこに貼ってますかぁ?
>
> Main()メソッドの中に貼ってくださいね。
> あと、必要な using とかもちゃんと追加してくださいね。
>
> 万が一、この意味が分からない場合は、さすがに、もう少し勉強されることをお勧めします。
>

>この意味が分からない場合は、さすがに、もう少し勉強されることをお勧めします。

すいません。
勉強不足でお手数をお掛けします。

>コード、どこに貼ってますかぁ?

以下に貼り付けの手順です。

1)Visual Studio 2019 を起動
2)新しいプロゼクトの作成
3)新しいプロゼクトの作成画面で
    全ての言語のドロップダウンでc#を選択
    コンソールアプリ(.net Framework) を選択
4)新しいプロゼクトを構成します
    プロゼクト名 ConsoleApp2 を指定
    フレームワーク .NET Frameworks 4.7.2 (既定値)
5)サーバーエクスプローラー ツ-ルボックス
   テンプレート上の既定値で表示されるテンプレートのコードを削除して
   教えてもらったコードをコピペ

   メニュー上のDebugをReleaseにして
   ビルド > ソルーションのビルド を選択

   出力画面 に
     ビルドを開始しました。
     (問題のエラー表示)  

----------------
>「C#9.0」どころか、「C#5.0」で作成したコードですよ。

すいません。
 c#のド素人なので難しいことは勉強不足で判りません。

 最初に提示したコードでは、1)-5)の手順で問題なくコンパイルされたので
 少しのコードの手直しで同じく実行ファイル(EXE)が作成されると簡単に考えていました。

 勉強は、続けたいと思いますが
  同じ手順でとりあえず修正して完走するコードを提示寝返ると嬉しいです。
引用返信 編集キー/
■97378 / inTopicNo.6)  Re[5]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ ぶなっぷ (274回)-(2021/04/30(Fri) 15:56:36)
全てをまるごと貼ってしまうこともできますが、
さすがに基礎の基礎は理解した方がいいと思うので、ヒントを言いますね。

まず、usingは以下のように修正してください。
(旧)
using System.IO;

(新)
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

そして、コードを置き換えるのは、Main()メソッドの中です。
static void Main(string[] args)
{
}
の中にコードを貼り付けてください。
引用返信 編集キー/
■97379 / inTopicNo.7)  Re[6]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ KonNo (4回)-(2021/04/30(Fri) 16:38:58)
2021/04/30(Fri) 17:20:42 編集(投稿者)
2021/04/30(Fri) 16:41:53 編集(投稿者)
2021/04/30(Fri) 16:41:29 編集(投稿者)

ヒントありがとうございます。
 以下のように修正しました。

結果、出力で以下のエラーが出ます。
  ビルドを開始しました...
1>------ ビルド開始: プロジェクト: ConsoleApp2, 構成: Release Any CPU ------
1>C:\Users\konno\source\repos\ConsoleApp2\ConsoleApp2\Program.cs(43,2,43,2): error CS1513: } が必要です
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========

つまり、43行目でエラーが出ているようなので43行目にマウスを近づけると
   CS1513: } が必要です
と表示されました。

ネットで調べると
コンパイラ エラー CS1513 は、「} が必要です。」と出ていたので
} が不足していると思い追加すると
今度は、エラー無くConsoleApp2.exeが出力されました。

ビルドを開始しました...
1>------ ビルド開始: プロジェクト: ConsoleApp2, 構成: Release Any CPU ------
1> ConsoleApp2 -> C:\Users\konno\source\repos\ConsoleApp2\ConsoleApp2\bin\Release\ConsoleApp2.exe
========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========

--------------------------------------
これでOKとJ:\ttest以下にテスト用のDATAを作成してテスト走行しました
ConsoleApp2.exeをJ:\ttestに配置してRUNするとエラーが出ませんが、一瞬でJ:\ttest内のDATAフォルダーを含めてが全て消え失せました。
作成されるであろう集められたファイルはありません。
つまり、J:\ttest内は空の状態でした。

参考フォルダー構造図
  https://imgur.com/2eSw05j


どこか?認識の間違いやアドバイスがありますか ?




(以下は、最下行に}を追加する前の途中のコードです。)

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

namespace ZapAll
{
class Program
{
private static readonly char separator = Path.DirectorySeparatorChar;

static void Main(string[] args)

{
var TgtDir = Directory.GetCurrentDirectory();
var tgtFiles = new Dictionary<string, FileInfo>();
var allFiles = Directory.EnumerateFiles(TgtDir, "*", SearchOption.AllDirectories).Select(x => new FileInfo(x));
var allFileGrps = allFiles.ToLookup(x => x.Name);
foreach (var files in allFileGrps)
{
int index = 0;
foreach (var file in files)
{
var fname = file.Name;
if (index++ > 0)
{
var fname_head = fname.Substring(0, fname.Length - file.Extension.Length);
fname = string.Format("{0}_{1}.{2}", fname_head, index, file.Extension);
}
tgtFiles.Add(fname, file);
}
}
foreach (var tgtFile in tgtFiles)
{
File.Move(tgtFile.Value.FullName, TgtDir + tgtFile.Key);
}
var allDirs = Directory.EnumerateDirectories(TgtDir, "*", SearchOption.AllDirectories);
foreach (var dir in allDirs.Reverse())
{
Directory.Delete(dir);
}
}
}
引用返信 編集キー/
■97380 / inTopicNo.8)  Re[7]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ Hongliang (1168回)-(2021/04/30(Fri) 18:41:30)
> var TgtDir = Directory.GetCurrentDirectory();

> File.Move(tgtFile.Value.FullName, TgtDir + tgtFile.Key);

TgtDirは末尾にパス区切り文字を付けないので、カレントがJ:\ttestでファイル名がhoge.txtだと
J:\ttesthoge.txt
みたいになっちゃって1つ上のフォルダに行っちゃいますね。

パスを結合する場合は、文字列を+でつなぐのではなく、Path.Combineメソッドを使うようにしたほうが安全です。
引用返信 編集キー/
■97381 / inTopicNo.9)  Re[8]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ KonNo (5回)-(2021/04/30(Fri) 19:19:07)
2021/04/30(Fri) 19:30:53 編集(投稿者)

No97380 (Hongliang さん) に返信
>> var TgtDir = Directory.GetCurrentDirectory();
>
>> File.Move(tgtFile.Value.FullName, TgtDir + tgtFile.Key);
>
> TgtDirは末尾にパス区切り文字を付けないので、カレントがJ:\ttestでファイル名がhoge.txtだと
> J:\ttesthoge.txt
> みたいになっちゃって1つ上のフォルダに行っちゃいますね。
>
> パスを結合する場合は、文字列を+でつなぐのではなく、Path.Combineメソッドを使うようにしたほうが安全です。

Hongliangさん、コードの解説ありがとうございます。

今チェックしたら、ファイルがJ:\に生成されていました。
最初の参考コードがConsoleApp2.exeが存在するディレクトリーに生成される仕様だったので
 勝手に新しいコードも同じ仕様だと判断してしまいました。

おかげさまで、
 コードを以下に変更して同じディレクトリーにファイルが生成されました。
File.Move(tgtFile.Value.FullName, tgtFile.Key);



引用返信 編集キー/
■97382 / inTopicNo.10)  Re[9]: フルパス付きでないファイル名(重複ファイルを考慮)
□投稿者/ KonNo (6回)-(2021/05/01(Sat) 04:50:49)
No97381 (KonNo さん) に返信
> 2021/04/30(Fri) 19:30:53 編集(投稿者)
>
> ■No97380 (Hongliang さん) に返信
> >> var TgtDir = Directory.GetCurrentDirectory();
>>
> >> File.Move(tgtFile.Value.FullName, TgtDir + tgtFile.Key);
>>
>>TgtDirは末尾にパス区切り文字を付けないので、カレントがJ:\ttestでファイル名がhoge.txtだと
>>J:\ttesthoge.txt
>>みたいになっちゃって1つ上のフォルダに行っちゃいますね。
>>
>>パスを結合する場合は、文字列を+でつなぐのではなく、Path.Combineメソッドを使うようにしたほうが安全です。
>
> Hongliangさん、コードの解説ありがとうございます。
>
> 今チェックしたら、ファイルがJ:\に生成されていました。
> 最初の参考コードがConsoleApp2.exeが存在するディレクトリーに生成される仕様だったので
>  勝手に新しいコードも同じ仕様だと判断してしまいました。
>
> おかげさまで、
>  コードを以下に変更して同じディレクトリーにファイルが生成されました。
> File.Move(tgtFile.Value.FullName, tgtFile.Key);
>
>
>
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -