File

作成

ファイルを作成し、そのストリームを取得できます。そのときファイルが存在しないならば、作成されます。

戻り値の型 メソッド 機能 同等の処理
FileStream Create(String) 読み取り、書き込み用にファイルを作成。すでに存在する場合は上書き new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, FileStream.DefaultBufferSize) Create - file.cs
StreamWriter CreateText(String) 書き込み用にテキストファイルを作成。すでに存在する場合は上書き (FileModeはCreate) new StreamWriter(path,false) CreateText - file.cs
StreamWriter AppendText(String) 書き込み用にテキストファイルを作成。すでに存在する場合は追記 new StreamWriter(path,true) AppendText - file.cs
       

Create()

public static System.IO.FileStream Create (string path);
Create(String) - File.Create Method (System.IO) | Microsoft Learn
string path = "sample.txt";
using (FileStream fs = File.Create(path))
{
    byte value = (byte)'A';
    fs.WriteByte(value);
}

コピー

public static void Copy (string sourceFileName, string destFileName);
Copy(String, String) - File.Copy Method (System.IO) | Microsoft Learn

保存先のdestFileNameが存在していると、IOExceptionが発生します。これを上書きするようにするには、第3引数を持つオーバーロードでtrueを指定します。

移動

public static void Move (string sourceFileName, string destFileName);
Move(String, String) - File.Move Method (System.IO) | Microsoft Learn

異なる名前で同じディレクトリへ移動することで、ファイル名の変更 (rename) として機能させられます。

destFileNameの位置にファイルが存在していると、「既に存在するファイルを作成することはできません。(Cannot create a file when that file already exists.)」としてIOExceptionが投げられます。そのときのHResultプロパティの値は、0x800700B7 (-2147024713) で、0xB7 (183) ERROR_ALREADY_EXISTSの意味です。この場合.NET Core 3.0以降ならば、第3引数をtrueとすることで上書きさせられます。それ以外では先に削除してから移動するか、安全にはCopy()で上書きしてから削除するかReplace()で置換します。

sourceFileNameが使用中だと、「パス '**' へのアクセスが拒否されました。 (Access to the path '**' is denied.)」としてIOExceptionが投げられます。そのときのHResultプロパティの値は、0x80131620 (-2146232800) です。

PathTooLongExceptionが投げられるパスの長さの基準は、.NET Framework 4.6.2より前ならば260文字で、以降ならば基本的に32767 (Int16.MaxValue) 文字となります。Remarks - PathTooLongException Class (System.IO) | Microsoft Learn

置換

指定のファイルを、別のファイルに置き換えられます。

public static void Replace (
    string sourceFileName,
    string destinationFileName,
    string destinationBackupFileName,
    bool ignoreMetadataErrors
    );
Replace(String, String, String, Boolean) - File.Replace メソッド (System.IO) | Microsoft Learn

sourceFileNameを、destinationFileNameに置き換えられます。つまりsourceFileNameが、destinationFileNameの位置に移動します。これら2つのファイルが存在していないと、FileNotFoundExceptionが投げられます。

  • sourceFileNamedestinationFileNameは同じボリュームとする。
  • バックアップが不要ならばdestinationBackupFileNameをnullとする。destinationBackupFileNameがすでに存在していると、それに上書きされる。
  • ignoreMetadataErrorsをtrueとすると、Win32のREPLACEFILE_IGNORE_MERGE_ERRORSフラグが設定される。これをを省略すると、falseが指定される。Replace - file.cs

このメソッドは内部ではWin32のReplaceFile()を呼ぶだけのため、処理はそれに準じます。そのため次の属性が保持されます。 Replace - file.cs Remarks - ReplaceFileA 関数 (winbase.h) - Win32 apps | Microsoft Learn

  • 作成日時 (Creation time)
  • 短いファイル名 (Short file name)
  • オブジェクト識別子 (Object identifier)
  • DACL (DACLs)
  • セキュリティ リソース属性 (Security resource attributes)
  • 暗号化 (Encryption)
  • 圧縮 (Compression)
  • 置換ファイルにまだ含まれていない、名前付きストリーム (Named streams not already in the replacement file)

FileSystemWatcherで変更を監視すると、バックアップを作成する場合は

File.Replace("src.txt", "dest.txt", "dest_bk.txt");
Renamed : dest.txt -> dest_bk.txt
Renamed : src.txt -> dest.txt

のように名前が変更されるだけですが、作成しないと

File.Replace("src.txt", "dest.txt", null);
Created : dest.txt~RF***.TMP
Deleted : dest.txt~RF***.TMP
Renamed : dest.txt -> dest.txt~RF***.TMP
Renamed : src.txt -> dest.txt
Deleted : dest.txt~RF***.TMP

のように一時ファイルが作成された上で削除されます。

オープン

ファイルを開き、そのストリームを取得できます。

戻り値の型 メソッド 機能 同等の処理 ファイルが存在しない場合
FileStream Open(String, FileMode) 読み取り、書き込み用にファイルを開く new FileStream(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None) Open - file.cs FileModeの指定による
FileStream OpenRead(String) 読み取り用にファイルを開く new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read) OpenRead - file.cs FileNotFoundException例外
StreamReader OpenText(String) 読み取り用にテキストファイルを開く new StreamReader(path) OpenText - file.cs FileNotFoundException例外
FileStream OpenWrite(String) 書き込み用にファイルを開く new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None) OpenWrite - file.cs ファイルを作成する

Open()

public static System.IO.FileStream Open (
    string path,
    System.IO.FileMode mode,
    System.IO.FileAccess access,
    System.IO.FileShare share
    );
Open(String, FileMode, FileAccess, FileShare) - File.Open Method (System.IO) | Microsoft Learn

accessを省略したとき、modeがAppendならばWriteに、それ以外ならばReadWriteになります。またshareを省略するとNoneになります。Open - file.cs

読み取り専用のファイルを開くときにFileAccess.Readを指定しないと、UnauthorizedAccessExceptionが発生します。

FileStream fileStream
  = File.Open("sample.dat", FileMode.Create, FileAccess.Write, FileShare.Read);
FileMode列挙型
列挙子 数値 意味
CreateNew 1 ファイルを作成する。すでに存在するならばIOExceptionが投げられる
Create 2 ファイルが存在するならばTruncateと同じ、存在しないならばCreateNewと同じ
Open 3 ファイルを開く。存在しないならばFileNotFoundExceptionが投げられる
OpenOrCreate 4 ファイルが存在するならば開く、存在しないならば作成する
Truncate 5 ファイルを開き、サイズが0バイトに切り詰められる (truncate)
Append 6 ファイルが存在するならば開き末尾までシークする、存在しないならば作成する
FileMode Enum (System.IO) | Microsoft Learn
  • Truncate以外で開いたときは、既存の内容が維持されたまま上書きされます。つまり"ABC"という内容のファイルに"X"と書き込むと、"XBC"という内容となります。
  • Append以外で開いたときも、FileStream.Seek()で末尾までシークできます。
  • いずれの方法で開いて書き換えたときも、ファイルの作成日時は維持されます。
FileAccess列挙型
列挙子 数値 意味
Read 1 ファイルから読み取れる
Write 2 ファイルに書き込める
ReadWrite 3 ファイルからの読み取りと書き込みをできる
FileAccess Enum (System.IO) | Microsoft Learn
FileShare列挙型
列挙子 数値 意味
None 0 現在のファイルの共有を拒否する。ファイルを閉じるまで、ファイルを開く要求は失敗する
Read 1 読み取り用にファイルを開くことを許可する。ファイルを閉じるまで、ファイルを読み取り用に開く要求は失敗する
Write 2 書き込み用にファイルを開くことを許可する
ReadWrite 3 読み取りまたは書き込み用にファイルを開くことを許可する
Delete 4 削除を許可する
Inheritable 16 子プロセスがファイル ハンドルを継承できるようにする。Win32では直接サポートされない
FileShare Enum (System.IO) | Microsoft Learn
string path = "sample.dat";
FileStream fs1 = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
FileStream fs2 = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); // ok
FileStream fs3 = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None); // IOException「別のプロセスで使用されているため、プロセスはファイル 'sample.dat' にアクセスできません。」

削除

指定ファイルを削除できます。

public static void Delete(
    string path
)
File.Delete(String) メソッド (System.IO) | Microsoft Learn

下表のような状況で例外が投げられます。

状況 例外
ファイルまでのパスが存在しない System.IO.DirectoryNotFoundException
ファイルは存在するが、使用中 System.IO.IOException
ファイルは存在するが、読み取り専用 System.UnauthorizedAccessException

DeleteFile()でERROR_FILE_NOT_FOUNDが返されたときは無視されるため、ファイルまでのパスは存在するがそこにファイルが存在しないときは、例外は投げられず何も通知されません。 Delete - file.cs

さまざまな要因で削除に失敗するため、File.Exists()でアクセスできることを確認してから削除するのが確実です。

存在確認

public static bool Exists (string path);
File.Exists(String) Method (System.IO) | Microsoft Learn

pathにアクセス可能ならば、trueが返されます。アクセスできなければfalseとなり、それには次のような場合も該当します。

  • pathがnull、空文字列、または無効なパス
  • pathがディレクトリを表している
  • ファイルは存在しているが、アクセス権を持たない

読み込み

戻り値 メソッド 機能
IEnumerable<string> ReadLines(String) ファイルの行を読み込める
string[] ReadAllLines(String) ファイルのすべての行を読み込める
string ReadAllText(String) ファイルのすべてのテキストを読み込める
byte[] ReadAllBytes(String) ファイルの内容をバイト配列に読み込める

情報

Fileクラス

string path = "sample.txt";

// 取得
DateTime dateTime1 = File.GetCreationTime(path);   // 作成日時 (Created)
DateTime dateTime2 = File.GetLastWriteTime(path);  // 更新日時 (Modified)
DateTime dateTime3 = File.GetLastAccessTime(path); // アクセス日時 (Accessed)
FileAttributes attributes = File.GetAttributes(path); // 属性

// 設定
File.SetCreationTime(path, DateTime.Now);
File.GetCreationTime メソッド (String) (System.IO) | MSDN

指定のファイルが存在しない場合、GetCreationTime()などの日時を取得するメソッドからは、ローカル時間に調整された1601/01/01 0:00:00(UTC) が返されます。一方でGetAttributes()からはFileNotFoundExceptionが投げられます。

BitLockerによりロックされている場合は、「このドライブは、BitLocker ドライブ暗号化でロックされています。コントロール パネルからドライブのロックを解除してください。(This drive is locked by BitLocker Drive Encryption. You must unlock this drive from Control Panel.)」そしてHResultは0x80370000 (-2143879168) で、IOExceptionが投げられます。

FileInfoクラス

同様の内容は、FileInfoではプロパティとして取得できます。

string path = "sample.txt";
FileInfo fileInfo = new FileInfo(path);

// 取得
DateTime dateTime1 = fileInfo.CreationTime;   // 作成日時
DateTime dateTime2 = fileInfo.LastWriteTime;  // 更新日時
DateTime dateTime3 = fileInfo.LastAccessTime; // アクセス日時
FileAttributes attributes = fileInfo.Attributes; // 属性

long size = fileInfo.Length; // サイズ

// 設定
fileInfo.CreationTime = DateTime.Now;
FileSystemInfo.CreationTime プロパティ (System.IO) | MSDN

指定のファイルが存在しない場合、File.GetAttributes()では例外が投げられますが、FileInfo.Attributesからは-1が返されますc# - Why is the FileAttributes value for a file which does not exist -1? - Stack Overflow

FileAttributes 列挙型

ファイルとディレクトリの属性を表します。

列挙子 内容
ReadOnly 1 読み取り専用
Hidden 2 隠しファイル
System 4 システム ファイル
Directory 16 ファイルはディレクトリ
Archive 32 増分バックアップ操作対象としてマークされている
Device 64 (将来使用するための予約)
Normal 128 特別な属性を持たない標準ファイル
Temporary 256 一時ファイル
SparseFile 512 スパース ファイル (データの大部分が0である大きなファイル)
ReparsePoint 1024 リパース ポイント (ファイルまたはディレクトリに関連付けられたユーザー定義のデータ ブロック) が含まれている
Compressed 2048 圧縮ファイル
Offline 4096 ファイルはオフライン
NotContentIndexed 8192 コンテンツ インデックス サービスでインデックスされない
Encrypted 16384 ファイルまたはディレクトリは、暗号化されている (ファイルの場合は、ファイルのすべてのデータが暗号化されている。 ディレクトリの場合は、新規作成されるファイルおよびディレクトリが既定で暗号化される)
IntegrityStream 32768 ファイルまたはディレクトリには、データ整合性のサポートが含まれる
NoScrubData 131072 ファイルまたはディレクトリは、データ整合性のスキャン対象から除外される
FileAttributes 列挙型 (System.IO) | Microsoft Learn

ロック状態の検出

ロックされているかどうかは、アクセス時に発生する例外から調べられます。

try
{
    using (File.Open(filePath, FileMode.Open, FileAccess.Read)) { }
}
catch (IOException e)
{
    int errorCode = e.HResult & 0xffff;
    if (errorCode == 0x20 || errorCode == 0x21)
    {
        // ロックされている
    }
}
c# - How to check for file lock? - Stack Overflow .net - How can I programmatically tell if a caught IOException is because the file is being used by another process, without resorting to parsing the exception's Message property? - Stack Overflow

.NET 4.5より前はException.HResultのアクセス修飾子がprotectedとなっているため、それの代わりに

int errorCode = Marshal.GetHRForException(e) & 0xffff;

のようにGetHRForException()から取得する必要があります。Community Additions - Exception.HResult Property (System)

[SecurityCriticalAttribute]
public static int GetHRForException(
    Exception e
)
Marshal.GetHRForException メソッド (Exception) (System.Runtime.InteropServices) | MSDN

エラーコードの意味は、それぞれ下表のように定義されています。

コード 定数 意味 例外メッセージ
32 (0x20) ERROR_SHARING_VIOLATION 他のプロセスによって使用されているため、プロセスはファイルにアクセスできない。共有違反 「別のプロセスで使用されているため、プロセスはファイル '***' にアクセスできません。」
33 (0x21) ERROR_LOCK_VIOLATION 他のプロセスがファイルの一部をロックしているため、プロセスはファイルにアクセスできない。 「プロセスはファイルにアクセスできません。別のプロセスがファイルの一部をロックしています。」
システム エラー コード (0 から 499) (WinError.h) - Win32 apps | Microsoft Learn

ロック解除を待つ

IOExceptionが投げられなくなるまで、くりかえしファイルにアクセスします。Wait until file is unlocked in .NET - Stack Overflow

ロックしているプロセスの取得

Win32の再起動マネージャー (Restart Manager) で、ファイルをロックしているプロセスの情報を得られます。

DWORD RmGetList(
  [in]                DWORD              dwSessionHandle,
  [out]               UINT               *pnProcInfoNeeded,
  [in, out]           UINT               *pnProcInfo,
  [in, out, optional] RM_PROCESS_INFO [] rgAffectedApps,
  [out]               LPDWORD            lpdwRebootReasons
);
RmGetList function (restartmanager.h) - Win32 apps | Microsoft Learn

lpdwRebootReasonsで返される値の意味は、次のようになります。

typedef enum _RM_REBOOT_REASON {
    RmRebootReasonNone = 0x0,               // Reboot not required
    RmRebootReasonPermissionDenied = 0x1,   // Current user does not have permission to shut down one or more detected processes
    RmRebootReasonSessionMismatch = 0x2,    // One or more processes are running in another TS session.
    RmRebootReasonCriticalProcess = 0x4,    // A critical process has been detected
    RmRebootReasonCriticalService = 0x8,    // A critical service has been detected
    RmRebootReasonDetectedSelf = 0x10       // The current process has been detected
} RM_REBOOT_REASON;
RestartManager.h RM_REBOOT_REASON (restartmanager.h) - Win32 apps | Microsoft Learn
Microsoft Learnから検索