C#: ファイル入出力

1. 静的クラスの定義

File クラスは、ファイル操作のための静的メソッドを提供しており、1回限りの読み取り・書き込みや単純な操作に適しています。代表的なメソッドには、ReadAllText、WriteAllText、AppendAllText、Exists、Copy、Move、Delete、ReadAllLines などがあります。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
Hello, World!
Line: Hello, World!
Line: Appended line.
Exists: True

2. ディレクトリの静的クラス

Directory クラスは、ディレクトリの操作(作成、削除、存在確認、サブディレクトリやファイルの一覧表示など)を行うための静的メソッドを提供しています。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
Exists: True
Files:
  a.txt
  b.txt
Dirs:
  SubDir

3. FileInfo クラスと DirectoryInfo クラス

FileInfo および DirectoryInfo はインスタンスクラスであり、同じファイルやディレクトリに対して複数の操作を実行するのに適しています。これらのクラスを使用することで、パスの検証を繰り返し行う必要がなくなり、パフォーマンスが向上します。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
Name: demo.txt
Length: 14
Extension: .txt
FullName: ...\demo.txt
Dir exists: True
Sub: Child

4. Stream抽象クラスとFileStream

Stream は、すべてのストリームの抽象基底クラスであり、Read、Write、Seek メソッドを提供します。FileStream はその派生クラスであり、低レベルのバイト単位の読み書き操作を実行します。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
FileStream demo

5. StreamReader と StreamWriter

StreamReader および StreamWriter は、エンコーディング処理をカプセル化したテキスト指向の読み取り/書き込みクラスであり、FileStream よりも使いやすくなっています。StreamReader は ReadLine を通じて行単位で読み込み、StreamWriter は WriteLine を通じて書き込みを行います。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
First line
Second line
No newline here appended.

6. BinaryReader と BinaryWriter

BinaryReader および BinaryWriter は、バイナリデータの読み取りおよび書き込みに使用され、さまざまなプリミティブ型(int、double、string など)をサポートしています。これらは、テキスト以外の形式の処理に適しています。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
Int: 42, Double: 3.14, String: hello

7. パスヘルパークラス

Path クラスは、パス操作のための静的メソッドを提供しており、手動での文字列連結によるエラーを防ぐため、クロスプラットフォームでパス区切り文字を処理します。代表的なメソッドには、Combine、GetExtension、GetFileName、GetDirectoryName、GetTempPath などがあります。

▶ サンプル

CSHARP
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()}");
▶ 試してみよう
TEXT 📖 参照専用
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 インターフェースを実装しています。

▶ サンプル

CSHARP
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);
▶ 試してみよう
TEXT 📖 参照専用
Block using
True

❓ よくある質問

Q 「File」と「FileInfo」、どちらを使うべきですか?
A 1回限りの操作の場合は、「File」の静的メソッドの方が簡潔です。一方、同じファイルに対して複数の操作を行う場合は、「FileInfo」の方がパフォーマンスに優れています。
Q FileStream と StreamReader の違いは何ですか?
A FileStream はバイト単位で読み書きを行いますが、StreamReader はエンコーディングを自動的に処理してテキストを読み書きします。テキスト操作を行う場合は、StreamReader を使用することをお勧めします。
Q using ステートメント内で例外が発生した場合、リソースは解放されますか?
A はい。using は try/finally 文にコンパイルされるため、例外がスローされた場合でも Dispose が呼び出されます。
Q なぜパスを文字列で連結してはいけないのですか?
A オペレーティングシステムによって、パス区切り文字が異なります。Path.Combine を使用すれば、クロスプラットフォームでのパス連結を安全に行うことができます。

📖 まとめ

📝 練習問題

  1. File.WriteAllText を使用して詩を保存し、その後 File.ReadAllText を使用してそれを読み込んで出力するプログラムを作成してください。
  2. Directory.CreateDirectory を使用して多階層のディレクトリを作成し、そのサブディレクトリとファイルを順に処理して出力する
  3. StreamWriter を使用して 5 行のログエントリを書き込み、その後 StreamReader を使用して 1 行ずつ読み込み、行番号を出力する
  4. BinaryWriter を使用して一連の int 値を書き込み、その後 BinaryReader を使用してそれらを読み戻し、合計を計算する
  5. Path.Combine を使用してパスを結合し、ファイル名、拡張子、ディレクトリ名をそれぞれ個別に表示する
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%