はじめに
C#実践編では、実際の開発で必要になるスキルを学びます。第1回はファイル操作です。
C#ではSystem.IO名前空間のクラスを使用します。
テキストファイルの読み書き
ファイルを読む
using System.Text;
// ファイル全体を読み込む
string content = File.ReadAllText("sample.txt", Encoding.UTF8);
Console.WriteLine(content);
// 全行を配列として取得
string[] lines = File.ReadAllLines("sample.txt", Encoding.UTF8);
foreach (var line in lines)
{
Console.WriteLine(line);
}
// 1行ずつ読み込み(大容量ファイル向け)
foreach (var line in File.ReadLines("sample.txt", Encoding.UTF8))
{
Console.WriteLine(line);
}
// 非同期読み込み
string asyncContent = await File.ReadAllTextAsync("sample.txt", Encoding.UTF8);
ファイルに書き込む
using System.Text;
// 新規作成・上書き
File.WriteAllText("output.txt", "こんにちは\nC#\n", Encoding.UTF8);
// 追記
File.AppendAllText("output.txt", "追加の行\n", Encoding.UTF8);
// 複数行を書き込み
string[] lines = ["1行目", "2行目", "3行目"];
File.WriteAllLines("output.txt", lines, Encoding.UTF8);
// 非同期書き込み
await File.WriteAllTextAsync("output.txt", "内容", Encoding.UTF8);
usingステートメントによるリソース管理
ストリームは自動的に閉じられます。
using System.Text;
// 良い例(自動でDispose)
using (var reader = new StreamReader("file.txt", Encoding.UTF8))
{
string? line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
// ここでreaderは自動的に閉じられる
// C# 8.0以降のusing宣言
using var writer = new StreamWriter("output.txt", false, Encoding.UTF8);
writer.WriteLine("1行目");
writer.WriteLine("2行目");
// スコープを抜けると自動でDispose
StreamReader/StreamWriter
大容量ファイルの処理にはストリームが効果的です。
using System.Text;
// 読み込み
using var reader = new StreamReader("large.txt", Encoding.UTF8);
string? line;
while ((line = reader.ReadLine()) != null)
{
ProcessLine(line);
}
// 書き込み
using var writer = new StreamWriter("output.txt", append: false, Encoding.UTF8);
foreach (var item in data)
{
writer.WriteLine(item);
}
// StreamWriterのオプション
using var writerWithOptions = new StreamWriter(
path: "output.txt",
append: true,
encoding: Encoding.UTF8,
bufferSize: 4096);
FileStream
バイナリデータやより細かい制御が必要な場合に使用します。
// FileStreamの基本
using var stream = new FileStream(
"file.bin",
FileMode.Create,
FileAccess.Write);
byte[] data = [1, 2, 3, 4, 5];
stream.Write(data);
// FileModeの種類
// Create - 新規作成(既存は上書き)
// CreateNew - 新規作成(既存があるとエラー)
// Open - 既存を開く
// OpenOrCreate - 開くか新規作成
// Append - 追記モード
// Truncate - 既存を空にして開く
// FileAccessの種類
// Read, Write, ReadWrite
JSONファイルの操作
System.Text.Jsonを使用します(.NET Core 3.0+)。
using System.Text.Json;
// シリアライズ設定
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
// JSONを読み込む
string json = File.ReadAllText("user.json", Encoding.UTF8);
User? user = JsonSerializer.Deserialize<User>(json, options);
// JSONに書き込む
var newUser = new User("太郎", 25, ["C#", "Unity"]);
string outputJson = JsonSerializer.Serialize(newUser, options);
File.WriteAllText("output.json", outputJson, Encoding.UTF8);
// 非同期処理
await using var stream = File.OpenRead("user.json");
User? asyncUser = await JsonSerializer.DeserializeAsync<User>(stream, options);
record User(string Name, int Age, List<string> Skills);
Newtonsoft.Json(従来の方法)
using Newtonsoft.Json;
// JSONを読み込む
string json = File.ReadAllText("user.json");
User? user = JsonConvert.DeserializeObject<User>(json);
// JSONに書き込む
var newUser = new User("太郎", 25, new List<string> { "C#" });
string outputJson = JsonConvert.SerializeObject(newUser, Formatting.Indented);
File.WriteAllText("output.json", outputJson);
CSVファイルの操作
シンプルなCSV処理の例です。
using System.Text;
// CSV読み込み
List<Dictionary<string, string>> ReadCsv(string path)
{
var lines = File.ReadAllLines(path, Encoding.UTF8);
if (lines.Length == 0) return [];
var headers = lines[0].Split(',');
var result = new List<Dictionary<string, string>>();
for (int i = 1; i < lines.Length; i++)
{
var values = lines[i].Split(',');
var row = new Dictionary<string, string>();
for (int j = 0; j < headers.Length; j++)
{
row[headers[j]] = j < values.Length ? values[j] : "";
}
result.Add(row);
}
return result;
}
// CSV書き込み
void WriteCsv(string path, List<Dictionary<string, string>> data)
{
if (data.Count == 0) return;
var headers = data[0].Keys.ToList();
var lines = new List<string>
{
string.Join(",", headers)
};
foreach (var row in data)
{
var values = headers.Select(h => row.GetValueOrDefault(h, ""));
lines.Add(string.Join(",", values));
}
File.WriteAllLines(path, lines, Encoding.UTF8);
}
パス操作
// パスの結合
string path = Path.Combine("documents", "report.txt");
Console.WriteLine(path); // documents\report.txt (Windows)
// パス情報の取得
string filePath = @"C:\Users\user\documents\report.txt";
Console.WriteLine(Path.GetFileName(filePath)); // report.txt
Console.WriteLine(Path.GetFileNameWithoutExtension(filePath)); // report
Console.WriteLine(Path.GetExtension(filePath)); // .txt
Console.WriteLine(Path.GetDirectoryName(filePath)); // C:\Users\user\documents
// 絶対パスに変換
string absolute = Path.GetFullPath("file.txt");
Console.WriteLine(absolute);
// 一時ファイル
string tempPath = Path.GetTempPath();
string tempFile = Path.GetTempFileName();
ディレクトリ操作
// 存在確認
Console.WriteLine(File.Exists("sample.txt"));
Console.WriteLine(Directory.Exists("folder"));
// ファイル情報
var fileInfo = new FileInfo("sample.txt");
Console.WriteLine(fileInfo.Length); // バイト数
Console.WriteLine(fileInfo.CreationTime); // 作成日時
Console.WriteLine(fileInfo.LastWriteTime); // 更新日時
// ディレクトリ作成
Directory.CreateDirectory("new_folder");
Directory.CreateDirectory(@"a\b\c"); // 再帰的に作成
// ディレクトリ内のファイル一覧
string[] files = Directory.GetFiles(".");
string[] dirs = Directory.GetDirectories(".");
// パターンで検索
string[] txtFiles = Directory.GetFiles(".", "*.txt");
// 再帰的に検索
string[] allCsFiles = Directory.GetFiles(".", "*.cs", SearchOption.AllDirectories);
// EnumerateFiles(大量ファイル向け)
foreach (var file in Directory.EnumerateFiles(".", "*.txt"))
{
Console.WriteLine(file);
}
// ファイル削除
File.Delete("file.txt");
// ディレクトリ削除
Directory.Delete("empty_folder");
Directory.Delete("folder", recursive: true);
// コピーと移動
File.Copy("src.txt", "dst.txt", overwrite: true);
File.Move("old.txt", "new.txt", overwrite: true);
Directory.Move("old_dir", "new_dir");
実践例:ログファイル処理
using System.Text;
record ErrorEntry(int Line, string Content);
List<ErrorEntry> ParseLogFile(string logPath)
{
var errors = new List<ErrorEntry>();
int lineNum = 0;
foreach (var line in File.ReadLines(logPath, Encoding.UTF8))
{
lineNum++;
if (line.Contains("ERROR"))
{
errors.Add(new ErrorEntry(lineNum, line.Trim()));
}
}
return errors;
}
void SaveErrorReport(List<ErrorEntry> errors, string outputPath)
{
using var writer = new StreamWriter(outputPath, false, Encoding.UTF8);
writer.WriteLine($"エラーレポート - {DateTime.Now}");
writer.WriteLine(new string('=', 50));
writer.WriteLine();
foreach (var error in errors)
{
writer.WriteLine($"行 {error.Line}: {error.Content}");
}
writer.WriteLine();
writer.WriteLine($"合計: {errors.Count}件のエラー");
}
// 使用例
var errors = ParseLogFile("app.log");
SaveErrorReport(errors, "error_report.txt");
非同期ファイル操作
// 非同期読み込み
string content = await File.ReadAllTextAsync("file.txt", Encoding.UTF8);
string[] lines = await File.ReadAllLinesAsync("file.txt", Encoding.UTF8);
// 非同期書き込み
await File.WriteAllTextAsync("file.txt", "content", Encoding.UTF8);
await File.WriteAllLinesAsync("file.txt", lines, Encoding.UTF8);
// StreamReader/Writerの非同期メソッド
using var reader = new StreamReader("file.txt");
string? line = await reader.ReadLineAsync();
using var writer = new StreamWriter("file.txt");
await writer.WriteLineAsync("content");
まとめ
Fileクラスで簡単なファイル操作StreamReader/StreamWriterで大容量ファイル処理usingステートメントで安全なリソース管理System.Text.JsonでJSON操作Pathクラスでパス操作Directoryクラスでディレクトリ操作
次回は例外処理について学びます。