C#でファイル名を変更するにはFile.Move(元ファイルパス,後ファイルパス)
を使うのが一番ラクですが、実はこのメソッドには2つ落とし穴があるので、それを回避する方法を説明します。
フォルダ(ディレクトリ)では使えない
File
なので当たり前といえばそうですが、フォルダかどうかは気にせずファイル名を変更したいですね。
フォルダの場合は代わりにDirectory.Move()
を使用します。
そして、指定されたパスがフォルダかどうかはFileInfo.Attributes
から調べます。
publicstaticvoidRename(stringsourceFilePath,stringoutputFilePath){varfileInfo=newFileInfo(sourceFilePath);if(fileInfo.Attributes.HasFlag(FileAttributes.Directory)){Directory.Move(fileInfo.FullName,outputFilePath);}else{fileInfo.MoveTo(outputFilePath);}}
フォルダ(ディレクトリ)は大文字小文字だけの変更はできない
たとえば、C:\abc
→C:\ABC
といった変更は直接できません。ですので一度別のファイル名に変更してから再変更します。
publicstaticvoidRenameDirectory(stringsourceFilePath,stringoutputFilePath){if((String.Compare(sourceFilePath,outputFilePath,true)==0)){vartempPath=GetSafeTempName(outputFilePath);Directory.Move(sourceFilePath,tempPath);Directory.Move(tempPath,outputFilePath);}else{Directory.Move(sourceFilePath,outputFilePath);}}privatestaticstringGetSafeTempName(stringoutputFilePath){outputFilePath+="_";while(File.Exists(outputFilePath)){outputFilePath+="_";}returnoutputFilePath;}
なお、この問題はFile.Move()
では発生しません。謎い。
まとめ
以上2つの解決策をまとめると、以下のようになります。
他にもこんな落とし穴がある、とかあったら教えてください。
/// <summary>/// 確実にファイル/ディレクトリの名前を変更する/// </summary>/// <param name="sourceFilePath">変更元ファイルパス</param>/// <param name="outputFilePath">変更後ファイルパス</param>publicstaticvoidRename(stringsourceFilePath,stringoutputFilePath){varfileInfo=newFileInfo(sourceFilePath);if(fileInfo.Attributes.HasFlag(FileAttributes.Directory)){RenameDirectory(sourceFilePath,outputFilePath);}else{fileInfo.MoveTo(outputFilePath);}}/// <summary>/// 確実にディレクトリの名前を変更する/// </summary>/// <param name="sourceFilePath">変更元ファイルパス</param>/// <param name="outputFilePath">変更後ファイルパス</param>publicstaticvoidRenameDirectory(stringsourceFilePath,stringoutputFilePath){//Directory.Moveはなぜか、大文字小文字だけの変更だとエラーする//なので、大文字小文字だけの変更の場合は一度別のファイル名に変更するif((String.Compare(sourceFilePath,outputFilePath,true)==0)){vartempPath=GetSafeTempName(outputFilePath);Directory.Move(sourceFilePath,tempPath);Directory.Move(tempPath,outputFilePath);}else{Directory.Move(sourceFilePath,outputFilePath);}}/// <summary>/// 指定したファイルパスが他のファイルパスとかぶらなくなるまで"_"を足して返す/// </summary>privatestaticstringGetSafeTempName(stringoutputFilePath){outputFilePath+="_";while(File.Exists(outputFilePath)){outputFilePath+="_";}returnoutputFilePath;}
参考
https://dobon.net/vb/dotnet/file/filecopy.html
環境
VisualStudio2019
.NET Core 3.1
C#8