C#: ファイル入出力
1. 静的クラスの定義
File クラスは、ファイル操作のための静的メソッドを提供しており、1回限りの読み取り・書き込みや単純な操作に適しています。代表的なメソッドには、ReadAllText、WriteAllText、AppendAllText、Exists、Copy、Move、Delete、ReadAllLines などがあります。
▶ サンプル
using System;
using System.IO;
string path = "test.txt";
File.WriteAllText(path, "Hello, World!");
string content = File.ReadAllText(path);
Console.WriteLine(content);
File.AppendAllText(path, "\nAppended line.");
string[] lines = File.ReadAllLines(path);
foreach (string line in lines)
{
Console.WriteLine($"Line: {line}");
}
Console.WriteLine($"Exists: {File.Exists(path)}");
File.Copy(path, "copy.txt", overwrite: true);
File.Move("copy.txt", "moved.txt");
File.Delete("moved.txt");
File.Delete(path);
Hello, World!
Line: Hello, World!
Line: Appended line.
Exists: True
2. ディレクトリの静的クラス
Directory クラスは、ディレクトリの操作(作成、削除、存在確認、サブディレクトリやファイルの一覧表示など)を行うための静的メソッドを提供しています。
▶ サンプル
using System;
using System.IO;
string dir = "MyFolder";
Directory.CreateDirectory(dir);
Console.WriteLine($"Exists: {Directory.Exists(dir)}");
File.WriteAllText(Path.Combine(dir, "a.txt"), "aaa");
File.WriteAllText(Path.Combine(dir, "b.txt"), "bbb");
Directory.CreateDirectory(Path.Combine(dir, "SubDir"));
string[] files = Directory.GetFiles(dir);
Console.WriteLine("Files:");
foreach (string f in files)
{
Console.WriteLine($" {Path.GetFileName(f)}");
}
string[] dirs = Directory.GetDirectories(dir);
Console.WriteLine("Dirs:");
foreach (string d in dirs)
{
Console.WriteLine($" {Path.GetFileName(d)}");
}
Directory.Delete(dir, recursive: true);
Exists: True
Files:
a.txt
b.txt
Dirs:
SubDir
3. FileInfo クラスと DirectoryInfo クラス
FileInfo および DirectoryInfo はインスタンスクラスであり、同じファイルやディレクトリに対して複数の操作を実行するのに適しています。これらのクラスを使用することで、パスの検証を繰り返し行う必要がなくなり、パフォーマンスが向上します。
▶ サンプル
using System;
using System.IO;
FileInfo fi = new FileInfo("demo.txt");
fi.WriteAllText("File info demo");
Console.WriteLine($"Name: {fi.Name}");
Console.WriteLine($"Length: {fi.Length}");
Console.WriteLine($"Extension: {fi.Extension}");
Console.WriteLine($"FullName: {fi.FullName}");
fi.Delete();
DirectoryInfo di = new DirectoryInfo("DemoDir");
di.Create();
Console.WriteLine($"Dir exists: {di.Exists}");
di.CreateSubdirectory("Child");
foreach (DirectoryInfo child in di.GetDirectories())
{
Console.WriteLine($"Sub: {child.Name}");
}
di.Delete(recursive: true);
Name: demo.txt
Length: 14
Extension: .txt
FullName: ...\demo.txt
Dir exists: True
Sub: Child
4. Stream抽象クラスとFileStream
Stream は、すべてのストリームの抽象基底クラスであり、Read、Write、Seek メソッドを提供します。FileStream はその派生クラスであり、低レベルのバイト単位の読み書き操作を実行します。
▶ サンプル
using System;
using System.IO;
using System.Text;
string filePath = "data.bin";
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
byte[] data = Encoding.UTF8.GetBytes("FileStream demo");
fs.Write(data, 0, data.Length);
}
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.UTF8.GetString(buffer));
}
File.Delete(filePath);
FileStream demo
5. StreamReader と StreamWriter
StreamReader および StreamWriter は、エンコーディング処理をカプセル化したテキスト指向の読み取り/書き込みクラスであり、FileStream よりも使いやすくなっています。StreamReader は ReadLine を通じて行単位で読み込み、StreamWriter は WriteLine を通じて書き込みを行います。
▶ サンプル
using System;
using System.IO;
string path = "text.txt";
using (StreamWriter writer = new StreamWriter(path))
{
writer.WriteLine("First line");
writer.WriteLine("Second line");
writer.Write("No newline here ");
writer.Write("appended.");
}
using (StreamReader reader = new StreamReader(path))
{
string? line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
File.Delete(path);
First line
Second line
No newline here appended.
6. BinaryReader と BinaryWriter
BinaryReader および BinaryWriter は、バイナリデータの読み取りおよび書き込みに使用され、さまざまなプリミティブ型(int、double、string など)をサポートしています。これらは、テキスト以外の形式の処理に適しています。
▶ サンプル
using System;
using System.IO;
string path = "binary.dat";
using (BinaryWriter bw = new BinaryWriter(File.Open(path, FileMode.Create)))
{
bw.Write(42);
bw.Write(3.14);
bw.Write("hello");
}
using (BinaryReader br = new BinaryReader(File.Open(path, FileMode.Open)))
{
int num = br.ReadInt32();
double d = br.ReadDouble();
string s = br.ReadString();
Console.WriteLine($"Int: {num}, Double: {d}, String: {s}");
}
File.Delete(path);
Int: 42, Double: 3.14, String: hello
7. パスヘルパークラス
Path クラスは、パス操作のための静的メソッドを提供しており、手動での文字列連結によるエラーを防ぐため、クロスプラットフォームでパス区切り文字を処理します。代表的なメソッドには、Combine、GetExtension、GetFileName、GetDirectoryName、GetTempPath などがあります。
▶ サンプル
using System;
using System.IO;
string fullPath = Path.Combine("folder", "sub", "file.txt");
Console.WriteLine($"Combine: {fullPath}");
Console.WriteLine($"Extension: {Path.GetExtension(fullPath)}");
Console.WriteLine($"FileName: {Path.GetFileName(fullPath)}");
Console.WriteLine($"FileNameNoExt: {Path.GetFileNameWithoutExtension(fullPath)}");
Console.WriteLine($"DirectoryName: {Path.GetDirectoryName(fullPath)}");
Console.WriteLine($"TempPath: {Path.GetTempPath()}");
Combine: folder\sub\file.txt
Extension: .txt
FileName: file.txt
FileNameNoExt: file
DirectoryName: folder\sub
TempPath: ...\Temp\
8. using ステートメントと IDisposable
ファイルやストリームなどのリソースは、速やかに解放する必要があります。using 文を使用することで、例外が発生した場合でも Dispose メソッドが確実に呼び出されます。C# 8 以降では、using var宣言構文がサポートされています。クリーンアップが必要なすべてのリソースクラスは、IDisposable インターフェースを実装しています。
▶ サンプル
using System;
using System.IO;
string path = "using_demo.txt";
using (StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine("Block using");
}
using StreamReader sr = new StreamReader(path);
Console.WriteLine(sr.ReadLine());
File.Delete(path);
Console.WriteLine(typeof(Stream).GetInterface("IDisposable") != null);
Block using
True
❓ よくある質問
📖 まとめ
- ファイル静的クラスは、1回限りのファイル操作に適しています
- ディレクトリの静的クラスは、ディレクトリの作成、削除、および探索を管理します
- 同じ対象に対して複数の操作を行う場合は、FileInfo/DirectoryInfo のインスタンスクラスの方が適しています
- Stream はストリームの抽象基底クラスであり、FileStream はバイト単位の読み書き機能を提供します
- StreamReader/StreamWriter はエンコーディングをカプセル化し、テキスト入出力を簡素化する
- BinaryReader/BinaryWriter は、バイナリプリミティブ型のデータを処理します
- Pathクラスは、クロスプラットフォームでのパス操作を安全に処理します
- using 文を使用することで、IDisposable インターフェースを実装したリソースが速やかに解放されるようになります
📝 練習問題
- File.WriteAllText を使用して詩を保存し、その後 File.ReadAllText を使用してそれを読み込んで出力するプログラムを作成してください。
- Directory.CreateDirectory を使用して多階層のディレクトリを作成し、そのサブディレクトリとファイルを順に処理して出力する
- StreamWriter を使用して 5 行のログエントリを書き込み、その後 StreamReader を使用して 1 行ずつ読み込み、行番号を出力する
- BinaryWriter を使用して一連の int 値を書き込み、その後 BinaryReader を使用してそれらを読み戻し、合計を計算する
- Path.Combine を使用してパスを結合し、ファイル名、拡張子、ディレクトリ名をそれぞれ個別に表示する