ファイル

関連するクラス
  クラス 用途
  File ファイルを
  • 作成、コピー、削除、移動、オープン
ための静的メソッドを提供し、FileStream オブジェクトの作成を支援する
FileInfo ファイルを
  • 作成、コピー、削除、移動、オープン
ためのインスタンスメソッドを提供し、FileStream オブジェクトの作成を支援する
  Directory ディレクトリやサブディレクトリを
  • 作成、削除、移動、反復処理
ための、静的メソッドを提供する
DirectoryInfo ディレクトリやサブディレクトリを
  • 作成、削除、移動、反復処理
ための、インスタンスメソッドを提供する
  Path 複数のプラットフォームにまたがってディレクトリ文字列を処理するための、メソッドおよびプロパティを提供する
ファイルとディレクトリ - ファイルおよびストリーム入出力 - .NET | Microsoft Docs

File

メソッド 機能
Move(String, String) ファイルを新しい場所へ移動できる
 
メソッド - File クラス (System.IO) | MSDN

ファイルの作成

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

戻り値の型 メソッド 機能
FileStream Create(String) 読み取り、書き込み用に、ファイルを作成。すでに存在する場合は上書き

これは、new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, FileStream.DefaultBufferSize)として呼び出すことに相当 Create - file.cs

StreamWriter CreateText(String) 書き込み用に、テキストファイルを作成。すでに存在する場合は上書き

これは、new StreamWriter(path,false)として呼び出すことに相当 CreateText - file.cs

StreamWriter AppendText(String)

これは、new StreamWriter(path,true)として呼び出すことに相当 AppendText - file.cs

     
public static System.IO.FileStream Create (string path);
Create(String) - File.Create Method (System.IO) | Microsoft Docs
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 Docs

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

ファイルの移動

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

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

destFileNameの位置にファイルが存在していると、「既に存在するファイルを作成することはできません。」としてIOException例外が発生します。そのときのHResultプロパティの値は、0x800700B7 (-2147024713) で、0xB7 (183) ERROR_ALREADY_EXISTSの意味です。

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

ファイルのオープン

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

戻り値の型 メソッド 機能 ファイルが存在しない場合
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

ファイルを作成する
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 Docs
FileStream fileStream
  = File.Open("sample.dat", FileMode.Create, FileAccess.Write, FileShare.Read);

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

FileMode列挙型
列挙子 数値 意味
CreateNew 1  
Create 2  
Open 3  
OpenOrCreate 4 ファイルが存在する場合は開く、存在しない場合は作成する
Truncate 5  
Append 6  
FileMode Enum (System.IO) | Microsoft Docs
FileAccess列挙型
列挙子 数値 意味
Read 1  
Write 2  
ReadWrite 3  
FileAccess Enum (System.IO) | Microsoft Docs
FileShare列挙型
列挙子 数値 意味
None 0  
Read 1  
Write 2  
ReadWrite 3  
Delete 4  
Inheritable 16  
FileShare Enum (System.IO) | Microsoft Docs

ファイルの削除

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

public static void Delete(
    string path
)
File.Delete(String) メソッド (System.IO) | Microsoft Docs
  • ファイルまでのパスが存在しない … System.IO.DirectoryNotFoundException例外が発生
  • ファイルまでのパスは存在するが、そこにファイルが存在しない … 例外は発生しない
  • ファイルは存在するが、使用中 … System.IO.IOException例外が発生
  • ファイルは存在するが、読み取り専用 … System.UnauthorizedAccessException例外が発生

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

ファイルの存在確認

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

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

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

ファイルの情報

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

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

FileAttributes 列挙型

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

FileAttributes 列挙型 (System.IO) | Microsoft Docs

ファイルのロック状態の検出

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

try
{
    using (File.Open(filePath, FileMode.Open)) { }
}
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 他のプロセスがファイルの一部をロックしているため、プロセスはファイルにアクセスできない。
System Error Codes (0-499) (Windows) | MSDN

参考

FileInfo

同一のファイルに複数の処理をする場合には、Fileクラスの静的メソッドを呼ぶより、FileInfoクラスのインスタンスのメソッドを呼ぶようにします。Remarks - FileInfo Class (System.IO) | Microsoft Docs

public FileInfo (string fileName);
FileInfo(String) コンストラクター (System.IO) | Microsoft Docs
プロパティ 内容
string Name ファイルの名前。拡張子を含む
string FullName ファイルの絶対パス
string DirectoryName ディレクトリの絶対パス
string Extension ファイルの拡張子
bool Exists ファイルが存在するならば、true
DirectoryInfo Directory 親ディレクトリ
     

プロパティからの初回の読み取り時、FileInfoはRefresh()を呼び出しファイルの情報をキャッシュします。以降はそのキャッシュが返されるため、必要ならばRefresh()を明示的に呼び情報を更新します。Examples - FileInfo Class (System.IO) | Microsoft Docs

FileInfo fi = new FileInfo(@"c:\dir\sample.txt");

string str1 = fi.Name;          // "sample.txt"
string str2 = fi.FullName;      // "c:\\dir\\sample.txt"
string str3 = fi.DirectoryName; // "c:\\dir"
string str4 = fi.Extension;     // ".txt"
メソッド 機能
Refresh() オブジェクトの状態を更新できる
MoveTo(String) ファイルを新しい場所へ移動できる
   

MoveTo()で移動すると、ファイルのパスも更新されます。

FileInfo fi = new FileInfo("a.txt");
string name1 = fi.Name; // a.txt

fi.MoveTo("b.txt");
string name2 = fi.Name; // b.txt

Directory

メソッド 機能
   
メソッド - Directory Class (System.IO) | Microsoft Docs

ディレクトリの作成

メソッド 機能
CreateDirectory(String) 指定のディレクトリが存在していないならば、サブディレクトリも含めて作成する。さもなくば何もしない
CreateDirectory(String, DirectorySecurity) 指定のセキュリティでディレクトリを作成する。
オーバーロード - Directory.CreateDirectory Method (System.IO) | Microsoft Docs
public static DirectoryInfo CreateDirectory(
    string path
)
Directory.CreateDirectory メソッド (String) (System.IO) | MSDN

pathにはディレクトリのパスを指定します。これをファイルのパスとすると、それがディレクトリ名と解釈されて作成されます。つまり"c:\dir\sample.txt"と指定すると、c:\dirにsample.txtの名前のディレクトリが作成されます。これを適切に処理するには、GetDirectoryName()でディレクトリ名の部分のみを取得してから渡すようにします。

Directory.CreateDirectory(Path.GetDirectoryName(path));

ディレクトリの削除

Delete()で削除できます。

public static void Delete(
    string path
)
public static void Delete(
    string path,
    bool recursive
)
Directory.Delete メソッド (System.IO) | Microsoft Docs

指定パスが空ならばいずれのメソッドでも削除できますが、そうではない場合には2番目のメソッドでrecursiveをtrueとしなければ、「ディレクトリが空ではありません。」としてSystem.IO.IOExceptionが投げられます。

ディレクトリに読み取り専用のファイルが含まれているとUnauthorizedAccessExceptionが投げられディレクトリの削除に失敗しますが、読み取り専用ではないファイルは削除されます。

ディレクトリの存在確認

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

指定ディレクトリが存在しているならば、trueが返されます。次のような場合はfalseとなります。

  • ディレクトリが存在しない
  • 指定されたのがディレクトリではない
  • 確認時に次のような理由によりエラーが発生した
    • ファイル名に無効な文字が含まれている
    • ファイル名が長すぎる
    • ディスクの障害または喪失
    • ファイルの読み取り権限がない

確認前に末尾の空白は削除されます。大文字/小文字は区別されません。

string path = @"C:\dir\sample.txt";

bool result1 = Directory.Exists(path);                        // false
bool result2 = Directory.Exists(Path.GetDirectoryName(path)); // true

bool result3 = Directory.Exists("sample.txt");                // false

ディレクトリ内のファイル名などの取得

// ファイル名
string[] files1 = Directory.GetFiles(path);
string[] files2 = Directory.GetFiles(path, "*.txt"); // パターンに一致するもののみ
string[] files3 = Directory.GetFiles(path, "*.txt"
    , SearchOption.AllDirectories); // サブディレクトリも含める

// サブディレクトリ名
string[] directories = Directory.GetDirectories(path);

// ファイル名とサブディレクトリ名
string[] fileSystemEntries = Directory.GetFileSystemEntries(path);
メソッド 機能
GetFiles(String) ディレクトリ内のすべてのファイル名を取得できる
GetDirectories(String) ディレクトリ内のすべてのサブディレクトリ名を取得できる
GetFileSystemEntries(String) ディレクトリ内のすべてのファイル名とサブディレクトリ名を取得できる

これらのメソッドからは、パスを含むフルネーム (full name) で返されます。これをパスを除いた名前で取得するには、DirectoryInfo.GetFiles()などでFileInfoクラスなどで得て、そのNameプロパティから取得します。

EnumerateFiles()

.NET 4.0以降ならば、より効率的にファイル名などを取得できるEnumerateFiles()などを用います。

メソッド 機能
EnumerateFiles(String) ディレクトリ内のすべてのファイル名の、コレクションを取得できる
EnumerateDirectories(String) ディレクトリ内のすべてのサブディレクトリ名の、コレクションを取得できる
EnumerateFileSystemEntries(String) ディレクトリ内のすべてのファイル名とサブディレクトリ名の、コレクションを取得できる

またGetFiles()などで指定できるパターンは単純なものに限られるため、より複雑な条件はEnumerateFiles()などでコレクションとして取得した上で処理します。c# - Can you call Directory.GetFiles() with multiple filters? - Stack Overflow

IEnumerable<string> files = from file in
    Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
    where file.EndsWith(".txt") || file.EndsWith(".ini")
    select file;
EnumerateFiles(String, String) - Directory.EnumerateFiles Method (System.IO) | Microsoft Docs

作業ディレクトリ (working directory)

public static string GetCurrentDirectory()
Directory.GetCurrentDirectory メソッド (System.IO) | MSDN
public static void SetCurrentDirectory( string path )
Directory.SetCurrentDirectory メソッド (String) (System.IO) | MSDN

現在の作業ディレクトリ (current working directory) の取得と設定を行えます。これはEnvironment.CurrentDirectoryプロパティへの読み書きでも可能です。

設定時には、末尾の空白とバックスラッシュは削除されます。

Directory.SetCurrentDirectory("C:\\dir");
string dir1 = Directory.GetCurrentDirectory(); // "C:\\dir"

Directory.SetCurrentDirectory("C:\\dir ");
string dir2 = Directory.GetCurrentDirectory(); // "C:\\dir"

Directory.SetCurrentDirectory("C:\\dir\\");
string dir3 = Directory.GetCurrentDirectory(); // "C:\\dir"

なおVisual Studioでのデバッグ時に設定するだけならば、プロジェクトのプロパティを開き[デバッグ]タブの[作業ディレクトリ]でも設定できます。ただしこの設定は、単体テストのデバッグには適用されません。C# デバッグ構成のプロジェクト設定 | MSDN

C++での作業ディレクトリへのアクセス

アプリケーションのディレクトリ

AppDomain.CurrentDomain.BaseDirectoryから得られます。c# - Best way to get application folder path - Stack Overflow

またはAssembly.Locationからアプリケーションの実行ファイルのパスを取得し、そのディレクトリ名の部分を取得することでも得られます。c# - How can I get the application's path in a .NET console application? - Stack Overflow

System.Reflection.Assembly assembly = typeof(MyProgram).Assembly;
string directory = Path.GetDirectoryName(assembly.Location);

Application.StartupPathからでも得られますが、Visual Studioのテスト環境ではC:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindowのようなディレクトリが返されます。

指定パスがディレクトリかどうかの判別

File.Exists()で真ならばファイル、Directory.Exists()で真ならばディレクトリです。File.Exists メソッド (String) (System.IO) | MSDN

if(File.Exists(path))
{
    // pathはファイル
}
else if(Directory.Exists(path))
{
    // pathはディレクトリ
}
else
{
    // pathはファイルでもディレクトリでもない
}
Directory.Exists メソッド (String) (System.IO) | MSDN

なお属性から調べる方法もありますが、この方法では指定のパスが存在しないときにはFileNotFoundExceptionが、ネットワークドライブが存在しないときにはIOExceptionが投げられます。How do I distinguish a file or a folder in a drag and drop event in c#? - Stack Overflow

FileAttributes attributes = File.GetAttributes(path);
bool isDirectory = attributes.HasFlag(FileAttributes.Directory);

Directory.Exists()も内部では属性で判定しているため、効率を追求するならば、こちらの方法を用います。Exists - directory.cs

FileSystem

ファイルやディレクトリのための有用な機能が提供されます。

このクラスのメソッドは複数のファイルを一括して処理できないため、その必要があるときはWin32のSHFileOperation()やIFileOperationインターフェイスを用います。

FileSystem.CopyFile(@"C:\a.txt", @"C:\a1.txt", UIOption.AllDialogs); // ダイアログが表示され、1つめのファイルがコピーされる
FileSystem.CopyFile(@"C:\a.txt", @"C:\a2.txt", UIOption.AllDialogs); // ダイアログが再び表示され、2つめのファイルがコピーされる

SHFileOperation()

C#から呼び出す方法は、SHFileOperation() - NativeMethods.csにコードがあります。

IFileOperation

これをC#から呼び出す方法は.NET Matters: IFileOperation in Windows Vista | Microsoft Docsに解説があり、ソースコードはNetMatters2007_12.exeからダウンロードできます。

  • ファイルを同一のフォルダにコピーすると転送速度が表示されず、進捗も不適切に表示されます。
  • ファイルの削除時にごみ箱に移動されるかは、既定ではエクスプローラの設定に依存します。ただしUSBメモリなどのリムーバブルデバイスではごみ箱に移動されないため、つねに完全に削除されます。
  • 確認ダイアログが表示されるかどうかは、既定ではエクスプローラの設定に依存します。

Path

メソッド 取得できる情報
GetFileName(String) ファイル名 (拡張子あり)
GetFileNameWithoutExtension(String) ファイル名 (拡張子なし)
GetDirectoryName(String) ディレクトリ名
GetExtension(String) 拡張子
GetFullPath(String) 絶対パス
メソッド - Path クラス (System.IO) | Microsoft Docs

Pathクラスのたいていのメンバはファイルシステムを考慮せず、ファイルの実在も検証しません。

string path = @"c:\dir\sample.txt";

Path.GetFileName(path);                 // sample.txt
Path.GetFileNameWithoutExtension(path); // sample

Path.GetDirectoryName(path);            // c:\dir
Path.GetExtension(path);                // .txt

Path.GetFullPath("TEST.txt");
// c:\Users\UserName\documents\visual studio 2015\Projects\test\test\bin\x86\Debug\TEST.txt

ディレクトリ名を"sample.txt"とすることも可能なため、その場合はこれらの結果は誤っていることになります。またパス文字列にディレクトリ名を指定した場合、GetDirectoryName()は末尾のディレクトリ名を削除して返します。

string path = @"c:\dir1\dir2\sample.txt";

string r1 = Path.GetDirectoryName(path); // c:\dir1\dir2
string r2 = Path.GetDirectoryName(r1);   // c:\dir1

下表のメソッドで無効な文字を取得できますが、それらはファイルシステムに依存するため、正確性は保証されません。Remarks - Path.GetInvalidFileNameChars Method (System.IO) | Microsoft Docs

メソッド 機能
GetInvalidFileNameChars() ファイル名に使用できない文字を含む配列を取得できる
GetInvalidPathChars() パス名に使用できない文字を含む配列を取得できる

Combine()

文字列をパスとして結合できます。

public static string Combine (string path1, string path2);
Combine(String, String) - Path.Combine Method (System.IO) | Microsoft Docs
string path1 = Path.Combine("c:\\dir",   "sample.txt");        // "c:\\dir\\sample.txt"
string path2 = Path.Combine("c:\\dir\\", "sample.txt");        // "c:\\dir\\sample.txt"
string path3 = Path.Combine("dir",       "sample.txt");        // "dir\\sample.txt"
string path4 = Path.Combine("dir",       "c:\\dir\\sample.txt"); // "c:\\dir\\sample.txt"
string path5 = Path.Combine("dir",       "");                  // "dir"
string path6 = Path.Combine("dir\\",     "");                  // "dir\\"
string path7 = Path.Combine("dir",       "\\");                // "\\"
string path8 = Path.Combine("sample", ".txt"); // "sample\\.txt"

一時フォルダ

public static string GetTempPath()
Path.GetTempPath メソッド (System.IO) | MSDN

現在のユーザーの一時フォルダのパスを取得できます。どのパスを用いるかは、以下の順で決定されます。

  1. 環境変数 TMP
  2. 環境変数 TEMP (Windows Vista以降では、%LOCALAPPDATA%\Tempが既定値)
  3. 環境変数 USERPROFILE
  4. Windowsディレクトリ
public static string GetTempFileName()
Path.GetTempFileName メソッド (System.IO) | MSDN
public static string GetRandomFileName()
Path.GetRandomFileName メソッド (System.IO) | MSDN
  • GetTempFileName() … GetTempPath()で得られるパスに、無作為な名前に.tmpの拡張子を付けたファイルを作成し、そのパスを返す
  • GetRandomFileName() … フォルダ名またはファイル名として使用できる、無作為な名前を返す。たとえばkpvfojym.mqysdovvkjv.nfqといった名前

FileSystemWatcher

ディレクトリやファイルの変更を検出できます。

string path = @"C:\path"; // 監視するディレクトリ
string filter = "*.txt";  // 監視するファイルの種類

FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(path, filter);
fileSystemWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite;
fileSystemWatcher.IncludeSubdirectories = true;

FileSystemEventHandler OnChanged = delegate (object sender, FileSystemEventArgs e)
{
    Console.WriteLine($"{e.ChangeType} : {e.FullPath}");
};

RenamedEventHandler OnRenamed = delegate (object sender, RenamedEventArgs e)
{
    Console.WriteLine($"{e.ChangeType} : {e.OldFullPath} -> {e.FullPath}");
};

ErrorEventHandler OnError = delegate (object sender, ErrorEventArgs e)
{
    Exception exception = e.GetException();
    Console.WriteLine($"{exception.HResult} {exception.Message}");
};

fileSystemWatcher.Changed += OnChanged;
fileSystemWatcher.Created += OnChanged;
fileSystemWatcher.Deleted += OnChanged;
fileSystemWatcher.Renamed += OnRenamed;
fileSystemWatcher.Error += OnError;

fileSystemWatcher.EnableRaisingEvents = true;

ファイルシステムやアプリケーションによっては、複数のイベントが発生することがあります。Remarks - FileSystemWatcher.Changed Event (System.IO) | Microsoft Docs

エクスプローラで ファイルの新規作成
Created : C:\path\A.txt

エクスプローラで 名前の変更
Renamed : C:\path\A.txt -> C:\path\B.txt

エクスプローラで ファイルの削除
Deleted : C:\path\B.txt


エクスプローラで ファイルのコピー
Created : C:\path\C - コピー.txt
Changed : C:\path\C - コピー.txt

エクスプローラで 監視下のディレクトリ内でファイルを移動
Deleted : C:\path\Move1.txt
Created : C:\path\dir\Move1.txt

エクスプローラで 監視下のディレクトリへファイルを移動
Created : C:\path\Move2.txt
Changed : C:\path\Move2.txt
Changed : C:\path\Move2.txt

なおmove、copy、delコマンドで、名前の変更、削除、コピー、移動をした場合は、エクスプローラと同様にイベントが発生します。

コンストラクタ

public FileSystemWatcher (string path, string filter);
FileSystemWatcher(String, String) - FileSystemWatcher Constructor (System.IO) | Microsoft Docs

Filterプロパティに空文字列を設定すると"*.*"に変換されて設定されますが、引数のfilterにそれを設定するとそのまま空文字列に設定され、すべてのファイルが監視から除外されます。(.NET Framework 4.6で確認)

プロパティ

プロパティ 内容 既定値
  NotifyFilter   LastWrite | FileName | DirectoryName
  EnableRaisingEvents   false
  Filter   "*.*"
  IncludeSubdirectories   false
  InternalBufferSize   8192
  Path   ""
       

Filter

ディレクトリ内で監視するファイルを指定できます。これには「*」と「?」のワイルドカードを指定できますが、"*.txt|*.doc"のように複数のフィルタは指定できません。Remarks - FileSystemWatcher.Filter Property (System.IO) | Microsoft Docs

これはディレクトリに対しても適用されるため、たとえば*.txtと設定していると、名前が.txtで終わるディレクトリしか監視の対象になりません。

NotifyFilter

監視する変更の種類を指定できます。これはNotifyFilters列挙型の組み合わせで指定します。

NotifyFilters列挙型
列挙子 数値 説明
FileName 1 The name of the file.
DirectoryName 2 The name of the directory.
Attributes 4 The attributes of the file or folder.
Size 8 The size of the file or folder.
LastWrite 16 The date the file or folder last had anything written to it.
LastAccess 32 The date the file or folder was last opened.
CreationTime 64 The time the file or folder was created.
Security 256 The security settings of the file or folder.
Fields - NotifyFilters Enum (System.IO) | Microsoft Docs

すべての値を指定するには、(NotifyFilters)0x17fとすると簡単です。

EnableRaisingEvents

Pathプロパティに監視するパスを指定し、このEnableRaisingEventsをtrueとすることで監視が開始されます。これはEnableRaisingEventsをfalseにするか、Dispose()によりオブジェクトが破棄されると停止します。

なおWaitForChanged()を呼び出すと、このプロパティがfalseであってもイベントが発生します。

SynchronizingObject

Changedなどのイベントは、既定ではスレッドプールから呼ばれます。それを、このプロパティにControlクラスなどのISynchronizeInvokeを実装したクラスを設定することで、そのクラスと同一のスレッドから呼ばれるように変更できます。

InternalBufferSize

内部バッファのバイト数を表します。既定は8192バイトで各イベントは最大16バイトのメモリーを使用するため、512ほどのイベントが同時に発生するとオーバーフローする恐れがあります。かといってバッファのサイズを増加させるのは高価なため、NotifyFilterとIncludeSubdirectoriesで対象を制限し、イベントの発生を抑制します。

イベント

Changed

ファイルを処理する方法によっては、Changedイベントは繰り返し発生することがあります。Remarks - FileSystemWatcher.Changed Event (System.IO) | Microsoft Docs

メモ帳で 名前を付けて保存
Created : C:\path\Save.txt (ファイルの更新日時は 1601/01/01 9:00:00)
Deleted : C:\path\Save.txt
Created : C:\path\Save.txt (ファイルの更新日時は 現在の日時)
Changed : C:\path\Save.txt

メモ帳で 上書き保存
Changed : C:\path\Save.txt

Notepad++で 上書き保存
Changed : C:\path\Save.txt
Changed : C:\path\Save.txt

c# - FileSystemWatcher Changed event is raised twice - Stack Overflow

Error

内部バッファのオーバーフローなどにより、変更を監視できなくなったときに発生します。FileSystemWatcher.Error Event (System.IO) | Microsoft Docs

エラーの原因は、ハンドラのErrorEventArgs.GetException()からExceptionを取得することで判別でき、下表のような内容です。

HResult Message
0x80004005 "ネットワーク名が見つかりません。"
0x80131905 "ディレクトリ *** で、一度に加えられた変更が多すぎます。"

このイベントは監視できなくなったときに必ず発生するわけではなく、たとえばドライブが取り外されてもそれを検出できません。

MSDN (Microsoft Developer Network) から検索