6
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C#で確実にファイル名を変更する

Posted at

C#でファイル名を変更するにはFile.Move(元ファイルパス,後ファイルパス)を使うのが一番ラクですが、実はこのメソッドには2つ落とし穴があるので、それを回避する方法を説明します。

フォルダ(ディレクトリ)では使えない

Fileなので当たり前といえばそうですが、フォルダかどうかは気にせずファイル名を変更したいですね。
フォルダの場合は代わりにDirectory.Move()を使用します。
そして、指定されたパスがフォルダかどうかはFileInfo.Attributesから調べます。

public static void Rename(string sourceFilePath, string outputFilePath)
{
    var fileInfo = new FileInfo(sourceFilePath);

    if (fileInfo.Attributes.HasFlag(FileAttributes.Directory))
    {     
        Directory.Move(fileInfo.FullName, outputFilePath);
    }
    else
    {
        fileInfo.MoveTo(outputFilePath);
    }
}

フォルダ(ディレクトリ)は大文字小文字だけの変更はできない

たとえば、C:\abcC:\ABCといった変更は直接できません。ですので一度別のファイル名に変更してから再変更します。

public static void RenameDirectory(string sourceFilePath, string outputFilePath)
{
    if ((String.Compare(sourceFilePath, outputFilePath, true) == 0))
    {
        var tempPath = GetSafeTempName(outputFilePath);
        Directory.Move(sourceFilePath, tempPath);
        Directory.Move(tempPath, outputFilePath);
    }
    else
    {
        Directory.Move(sourceFilePath, outputFilePath);
    }
}

private static string GetSafeTempName(string outputFilePath)
{
    outputFilePath += "_";
    while (File.Exists(outputFilePath))
    {
        outputFilePath += "_";
    }
    return outputFilePath;
}

なお、この問題はFile.Move()では発生しません。謎い。

まとめ

以上2つの解決策をまとめると、以下のようになります。
他にもこんな落とし穴がある、とかあったら教えてください。

/// <summary>
/// 確実にファイル/ディレクトリの名前を変更する
/// </summary>
/// <param name="sourceFilePath">変更元ファイルパス</param>
/// <param name="outputFilePath">変更後ファイルパス</param>
public static void Rename(string sourceFilePath, string outputFilePath)
{
    var fileInfo = new FileInfo(sourceFilePath);

    if (fileInfo.Attributes.HasFlag(FileAttributes.Directory))
    {
        RenameDirectory(sourceFilePath, outputFilePath);
    }
    else
    {
        fileInfo.MoveTo(outputFilePath);
    }
}

/// <summary>
/// 確実にディレクトリの名前を変更する
/// </summary>
/// <param name="sourceFilePath">変更元ファイルパス</param>
/// <param name="outputFilePath">変更後ファイルパス</param>
public static void RenameDirectory(string sourceFilePath, string outputFilePath)
{
    //Directory.Moveはなぜか、大文字小文字だけの変更だとエラーする
    //なので、大文字小文字だけの変更の場合は一度別のファイル名に変更する
    if ((String.Compare(sourceFilePath, outputFilePath, true) == 0))
    {
        var tempPath = GetSafeTempName(outputFilePath);

        Directory.Move(sourceFilePath, tempPath);
        Directory.Move(tempPath, outputFilePath);
    }
    else
    {
        Directory.Move(sourceFilePath, outputFilePath);
    }
}

/// <summary>
/// 指定したファイルパスが他のファイルパスとかぶらなくなるまで"_"を足して返す
/// </summary>
private static string GetSafeTempName(string outputFilePath)
{
    outputFilePath += "_";
    while (File.Exists(outputFilePath))
    {
        outputFilePath += "_";
    }
    return outputFilePath;
}

参考

環境

VisualStudio2019
.NET Core 3.1
C#8

6
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?