C#でファイルを読み込む方法|csharp read fileの基本から行単位・全文読み込みまで解説
この記事では、「csharp read file」と検索している方に向けて、File.ReadAllText、File.ReadLines、StreamReaderなどを使った基本的なファイル読み込みを解説します。CSVやログファイルの実用例、文字コード、非同期処理、例外処理についても、サンプルコードを交えながら紹介します。
1. C#でファイルを読み込む前に知っておきたい基本
1-1. csharp read fileで検索するユーザーの目的とは
「csharp read file」というキーワードで検索する方の多くは、次のような処理を実装しようとしています。
txtファイルの内容を文字列として取得したい
ファイルを1行ずつ読み込みたい
CSVやログファイルを解析したい
大容量ファイルをメモリに負担をかけず処理したい
UTF-8やShift_JISを指定して文字化けを防ぎたい
非同期処理でファイルを読み込みたい
C#には複数の読み込み方法が用意されているため、最初に「ファイル全体が必要なのか」「1行ずつ処理するのか」「ファイルが大きいのか」を整理すると、適切なメソッドを選びやすくなります。
1-2. C#でファイル読み込みに使う主なクラスとメソッド
C#でテキストファイルを読み込むときは、主にSystem.IO名前空間のクラスを使用します。
代表的なメソッドは次のとおりです。
| クラス | メソッド | 読み込み結果 | 主な用途 |
|---|---|---|---|
File | ReadAllText | string | ファイル全体を一括取得 |
File | ReadAllLines | string[] | 全行を配列として取得 |
File | ReadLines | IEnumerable<string> | 必要な行を順番に取得 |
StreamReader | ReadLine | string | 1行ずつ細かく処理 |
StreamReader | ReadToEnd | string | 現在位置から末尾まで取得 |
File | ReadAllTextAsync | Task<string> | ファイル全体を非同期取得 |
File | ReadAllLinesAsync | Task<string[]> | 全行を非同期取得 |
Fileクラスは、ファイルの作成、コピー、削除、移動、読み書きなどを行う静的メソッドを提供しています。簡潔なコードでファイルを操作したい場合に便利です。
1-3. FileクラスとStreamReaderクラスの違い
Fileクラスの読み込みメソッドは、処理を短く書けることが特徴です。
string content = File.ReadAllText("sample.txt");一方、StreamReaderはファイルを開いてから、行単位や任意のタイミングでデータを読み取ります。
using var reader = new StreamReader("sample.txt");string? line;
while ((line = reader.ReadLine()) is not null){Console.WriteLine(line);}
StreamReaderは、指定した文字コードで文字データを読み込むためのクラスです。特に、標準的なテキストファイルを行単位で処理するときに適しています。
簡単な読み込みならFileクラス、読み込み処理を細かく制御したい場合はStreamReaderと考えるとよいでしょう。
1-4. 読み込み方法を選ぶ基準:全文・行単位・逐次処理
読み込み方法は、次の基準で選べます。
小さなファイルを全文取得する:
File.ReadAllText小さなファイルを行配列として取得する:
File.ReadAllLines大きなファイルを1行ずつ処理する:
File.ReadLines読み込み位置やタイミングを制御する:
StreamReaderUIやWebアプリで待機中のブロックを避ける:非同期メソッド
ファイルが小さく、処理が単純なら一括読み込みが便利です。大容量ファイルやログファイルでは、データを順番に処理する方法が適しています。
2. C#でファイルを全文読み込む方法
2-1. File.ReadAllTextでテキストファイルを一括読み込みする
File.ReadAllTextを使用すると、テキストファイルの内容を1つの文字列として取得できます。
string content = File.ReadAllText("sample.txt");Console.WriteLine(content);
ReadAllTextは、ファイルを開き、すべてのテキストを読み取ったあと、ファイルを閉じます。
設定ファイルやテンプレートファイルなど、ファイル全体をまとめて利用したい場合に便利です。
2-2. File.ReadAllTextの基本構文とサンプルコード
基本構文は次のとおりです。
string 変数名 = File.ReadAllText(ファイルパス);実際のコードでは、System.IO名前空間を読み込みます。
using System;using System.IO;string path = "message.txt";string content = File.ReadAllText(path);
Console.WriteLine(content);
ファイルの内容が次のようになっているとします。
こんにちはC#でファイルを読み込んでいます。contentには、改行を含むファイル全体の文字列が格納されます。
2-3. 文字コードを指定して全文読み込みする方法
文字コードを明示する場合は、第2引数にEncodingを指定します。
using System.IO;using System.Text;string path = "sample.txt";string content = File.ReadAllText(path, Encoding.UTF8);
Console.WriteLine(content);
UTF-8以外の文字コードを読み込む場合も、対応するEncodingオブジェクトを渡します。
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);Encoding shiftJis = Encoding.GetEncoding("shift_jis");string content = File.ReadAllText("sample-sjis.txt", shiftJis);
文字コードがあらかじめ分かっている場合は、明示的に指定したほうが環境差による文字化けを防ぎやすくなります。
2-4. ReadAllTextを使うメリット・デメリット
ReadAllTextのメリットは、コードが短く、読み込んだ内容をすぐ文字列として操作できることです。
例えば、文字列検索や置換を簡単に実行できます。
string content = File.ReadAllText("sample.txt");bool containsError = content.Contains("ERROR");string replaced = content.Replace("旧名称", "新名称");
一方で、ファイル全体をメモリ上に保持するため、大容量ファイルには向いていません。また、先頭の数行だけ必要な場合でも、ファイル全体を読み込むことになります。
2-5. 大きなファイルでReadAllTextを使う際の注意点
数百MBや数GBのファイルをReadAllTextで読み込むと、ファイル全体を文字列として保持するため、多くのメモリが必要になります。
大容量ファイルでは、File.ReadLinesまたはStreamReader.ReadLineを使用し、1行ずつ処理する方法が適しています。
foreach (string line in File.ReadLines("large-log.txt")){ProcessLine(line);}static void ProcessLine(string line){Console.WriteLine(line);}
必要なデータが見つかった時点で処理を終了することもできます。
foreach (string line in File.ReadLines("large-log.txt")){if (line.Contains("FATAL", StringComparison.OrdinalIgnoreCase)){Console.WriteLine(line);break;}}3. C#でファイルを行単位で読み込む方法
3-1. File.ReadAllLinesで全行を配列として読み込む
File.ReadAllLinesは、ファイルの各行をstring[]として返します。
string[] lines = File.ReadAllLines("sample.txt");foreach (string line in lines){Console.WriteLine(line);}
行番号を使ってアクセスできる点が特徴です。
string[] lines = File.ReadAllLines("sample.txt");if (lines.Length > 0){Console.WriteLine($"1行目: {lines[0]}");}
ただし、すべての行をメモリ上に保持するため、大容量ファイルではメモリ使用量に注意が必要です。
3-2. File.ReadLinesで1行ずつ遅延読み込みする
File.ReadLinesは、ファイルの行を必要になったタイミングで順番に取得します。
IEnumerable<string> lines = File.ReadLines("sample.txt");foreach (string line in lines){Console.WriteLine(line);}
全行を最初に配列へ格納するのではなく、列挙処理に合わせて読み進めるため、大きなファイルを処理しやすい方法です。
ただし、列挙中はファイルが使用されます。途中で列挙を終了した場合も、列挙子が適切に破棄されるよう、通常はforeachで処理します。
3-3. foreachを使ってファイルを1行ずつ処理する
File.ReadLinesとforeachを組み合わせると、簡潔に行単位の処理を書けます。
foreach (string line in File.ReadLines("users.txt")){Console.WriteLine($"読み込んだ行: {line}");}条件に一致する行だけを処理することも可能です。
foreach (string line in File.ReadLines("application.log")){if (!line.Contains("ERROR", StringComparison.OrdinalIgnoreCase)){continue;}Console.WriteLine(line);
}
LINQと組み合わせることもできます。
using System.Linq;IEnumerable<string> errorLines = File.ReadLines("application.log").Where(line => line.Contains("ERROR",StringComparison.OrdinalIgnoreCase));
foreach (string line in errorLines){Console.WriteLine(line);}
3-4. ReadAllLinesとReadLinesの違い
ReadAllLinesとReadLinesの主な違いは、全行を読み込むタイミングです。
| 項目 | ReadAllLines | ReadLines |
| 戻り値 | string[] | IEnumerable<string> |
| 読み込み | 最初に全行を取得 | 必要に応じて順次取得 |
| メモリ使用量 | ファイルサイズに応じて増える | 比較的抑えやすい |
| インデックスアクセス | 可能 | 直接は不可 |
| 大容量ファイル | 不向き | 向いている |
| 複数回の列挙 | 配列を再利用できる | 列挙のたびに再度読み込む可能性がある |
全行を並べ替えたり、何度も参照したりする場合はReadAllLinesが便利です。1回だけ順番に処理するなら、ReadLinesが適しています。
3-5. 行単位読み込みに向いているケース
行単位の読み込みは、次のような処理に向いています。
CSVやTSVを1レコードずつ処理する
ログファイルからエラー行を検索する
特定のキーワードを含む行を抽出する
ファイルの先頭数行だけ確認する
条件に一致した時点で処理を終了する
大容量ファイルを少ないメモリで処理する
例えば、先頭10行だけ読み込む場合は、LINQのTakeを利用できます。
using System.Linq;foreach (string line in File.ReadLines("sample.txt").Take(10)){Console.WriteLine(line);}
4. StreamReaderを使ってファイルを読み込む方法
4-1. StreamReaderの基本的な使い方
StreamReaderを使う場合は、ファイルパスをコンストラクターに渡します。
using System.IO;using var reader = new StreamReader("sample.txt");
string? content = reader.ReadLine();
Console.WriteLine(content);
StreamReaderは内部に読み込み位置を持ちます。ReadLineを呼び出すたびに、次の行へ進みます。
4-2. ReadLineで1行ずつ読み込むサンプルコード
ファイルの末尾まで読み込む場合は、ReadLineの戻り値がnullになるまで繰り返します。
using System;using System.IO;using var reader = new StreamReader("sample.txt");
string? line;
while ((line = reader.ReadLine()) is not null){Console.WriteLine(line);}
空行の場合、ReadLineは空文字列を返します。nullはファイルの末尾に到達したことを表します。
行番号を付ける場合は、カウンターを用意します。
using var reader = new StreamReader("sample.txt");int lineNumber = 0;string? line;
while ((line = reader.ReadLine()) is not null){lineNumber++;Console.WriteLine($"{lineNumber}: {line}");}
4-3. ReadToEndでファイル全体を読み込む方法
ReadToEndを使用すると、現在の読み込み位置からファイルの末尾までを文字列として取得できます。
using var reader = new StreamReader("sample.txt");string content = reader.ReadToEnd();
Console.WriteLine(content);
先に1行読み込んだ場合、ReadToEndが返すのは2行目以降です。
using var reader = new StreamReader("sample.txt");string? firstLine = reader.ReadLine();string remainingText = reader.ReadToEnd();
Console.WriteLine($"先頭行: {firstLine}");Console.WriteLine($"残り:\n{remainingText}");
ReadToEndも残りの内容をまとめてメモリへ読み込むため、大容量ファイルでは注意が必要です。
4-4. using文でファイルを安全に閉じる方法
StreamReaderは、使用後に破棄してファイルを閉じる必要があります。通常はusing文またはusing宣言を使用します。
using (var reader = new StreamReader("sample.txt")){string content = reader.ReadToEnd();Console.WriteLine(content);}usingブロックを抜けると、StreamReaderのDisposeが呼び出され、ファイルが閉じられます。例外が発生した場合も破棄処理が実行されます。
C# 8.0以降では、次のようなusing宣言も利用できます。
using var reader = new StreamReader("sample.txt");string content = reader.ReadToEnd();Console.WriteLine(content);
この場合は、現在のスコープを抜けるときに破棄されます。
4-5. StreamReaderを使うべき場面
StreamReaderは、次のような場面に適しています。
1行ずつ読み込みながら複雑な状態管理を行う
読み込み途中で処理を終了する
文字コードを明示して読み込む
FileStreamと組み合わせて共有モードなどを設定する非同期で1行ずつ読み込む
バッファーサイズなどを調整する
単純な全文読み込みならFile.ReadAllTextのほうが簡潔です。処理の自由度を重視する場合は、StreamReaderを選びましょう。
5. C#でCSVやログファイルを読み込む実用例
5-1. CSVファイルを1行ずつ読み込む
次のCSVファイルを読み込む例を考えます。
id,name,email1,山田太郎,yamada@example.com2,佐藤花子,sato@example.comヘッダーを除いて1行ずつ処理するコードは次のとおりです。
using System.IO;using System.Linq;foreach (string line in File.ReadLines("users.csv").Skip(1)){Console.WriteLine(line);}
ファイルが大きい場合も、ReadLinesであれば行を順番に処理できます。
5-2. カンマ区切りのデータを分割して処理する
単純なカンマ区切りであれば、Splitで各列に分割できます。
foreach (string line in File.ReadLines("users.csv").Skip(1)){string[] columns = line.Split(',');if (columns.Length < 3){continue;}string id = columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[0]</span>;string name = columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[1]</span>;string email = columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[2]</span>;Console.WriteLine($"ID={id}, 名前={name}, メール={email}");
}
ただし、次のように値の中にカンマが含まれるCSVは、単純なSplit(',')では正しく処理できません。
1,"山田,太郎",yamada@example.com引用符、引用符のエスケープ、値の途中の改行などを含む正式なCSVを扱う場合は、CSV仕様に対応したパーサーやライブラリを使用する必要があります。
5-3. ログファイルを順番に読み込んで解析する
ログファイルからエラー行だけを抽出する例です。
string path = "application.log";foreach (string line in File.ReadLines(path)){if (line.Contains("ERROR", StringComparison.OrdinalIgnoreCase)){Console.WriteLine(line);}}
エラー件数を数える場合は、次のように記述できます。
int errorCount = 0;foreach (string line in File.ReadLines("application.log")){if (!line.Contains("ERROR", StringComparison.OrdinalIgnoreCase)){continue;}
errorCount++;
}
Console.WriteLine($"エラー件数: {errorCount}");
LINQで件数を取得することも可能です。
int errorCount = File.ReadLines("application.log").Count(line => line.Contains("ERROR",StringComparison.OrdinalIgnoreCase));5-4. 空行や不要な行をスキップする方法
空行や空白だけの行は、string.IsNullOrWhiteSpaceで判定できます。
foreach (string line in File.ReadLines("settings.txt")){if (string.IsNullOrWhiteSpace(line)){continue;}Console.WriteLine(line);
}
コメント行も除外する場合は、次のように処理します。
foreach (string line in File.ReadLines("settings.txt")){if (string.IsNullOrWhiteSpace(line)){continue;}if (line.TrimStart().StartsWith("#", StringComparison.Ordinal)){continue;}Console.WriteLine(line);
}
LINQを使うと、条件をまとめて記述できます。
IEnumerable<string> validLines = File.ReadLines("settings.txt").Where(line => !string.IsNullOrWhiteSpace(line)).Where(line => !line.TrimStart().StartsWith("#",StringComparison.Ordinal));foreach (string line in validLines){Console.WriteLine(line);}
5-5. 読み込んだ内容をリストに格納する方法
単純に各行をリストへ格納する場合は、ToListを使用できます。
using System.Collections.Generic;using System.Linq;List<string> lines = File.ReadLines("sample.txt").ToList();
CSVの各行を分割して、タプルのリストへ格納する例は次のとおりです。
using System.Collections.Generic;using System.IO;using System.Linq;var users = new List<(int Id, string Name, string Email)>();
foreach (string line in File.ReadLines("users.csv").Skip(1)){string[] columns = line.Split(',');
if (columns.Length < 3){continue;}if (!int.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[0]</span>, out int id)){continue;}users.Add((Id: id,Name: columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[1]</span>,Email: columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[2]</span>));
}
ToListを実行すると、対象となる全行がリストとしてメモリ上に格納されます。大容量ファイルでは、本当に全件を保持する必要があるか検討しましょう。
6. ファイルパス指定と読み込み時の注意点
6-1. 絶対パスと相対パスの違い
絶対パスは、ドライブ名やルートディレクトリから始まる完全なパスです。
string path = @"C:\data\sample.txt";相対パスは、現在の作業ディレクトリを基準とするパスです。
string path = "data/sample.txt";絶対パスは参照先が明確ですが、実行環境が変わると利用できなくなることがあります。相対パスは移植しやすい一方、基準となるディレクトリを理解しておく必要があります。
6-2. 実行ファイルから見た相対パスの考え方
相対パスは、必ずしも実行ファイルが置かれているフォルダを基準にするわけではありません。通常は、プロセスの現在の作業ディレクトリを基準に解決されます。
現在の作業ディレクトリは、次のコードで確認できます。
Console.WriteLine(Environment.CurrentDirectory);IDE、コマンドライン、テストランナー、Webサーバーなど、起動方法によって作業ディレクトリが変わる可能性があります。
実行ファイルを基準にしたい場合は、AppContext.BaseDirectoryの利用を検討します。
6-3. File.Existsでファイルの存在を確認する
ファイルを読み込む前に、File.Existsで存在を確認できます。
string path = "sample.txt";if (!File.Exists(path)){Console.WriteLine("ファイルが見つかりません。");return;}
string content = File.ReadAllText(path);Console.WriteLine(content);
ただし、存在確認後に別の処理によってファイルが削除される可能性があります。そのため、File.Existsを使っていても、実際の読み込み処理では例外処理が必要です。
また、File.Existsがfalseを返しただけでは、ファイルが存在しないのか、パスが不正なのか、アクセスできないのかを完全には判別できません。
6-4. パスの区切り文字とエスケープの注意点
C#の通常の文字列では、バックスラッシュがエスケープ文字として扱われます。
string path = "C:\data\sample.txt";逐語的文字列リテラルを使うと、バックスラッシュを重ねずに記述できます。
string path = @"C:\data\sample.txt";複数のパス要素を結合する場合は、文字列を直接連結するよりPath.Combineを使用する方法が安全です。
string directory = @"C:\data";string fileName = "sample.txt";string path = Path.Combine(directory, fileName);
Path.Combineを使えば、OSに適した区切り文字でパスを組み立てられます。
6-5. AppContext.BaseDirectoryを使ったパス指定
AppContext.BaseDirectoryは、アプリケーションのベースディレクトリを取得するプロパティです。
実行ファイルと同じ場所にあるdataフォルダのファイルを読み込む場合は、次のように指定します。
string path = Path.Combine(AppContext.BaseDirectory,"data","sample.txt");string content = File.ReadAllText(path);
実際のパスを確認するには、コンソールへ出力します。
Console.WriteLine(path);開発環境では、設定したファイルがビルド出力先へコピーされているかも確認してください。
7. 文字コードを指定してファイルを読み込む方法
7-1. UTF-8のファイルを読み込む
UTF-8を明示して読み込む場合は、Encoding.UTF8を指定します。
using System.IO;using System.Text;string content = File.ReadAllText("sample.txt",Encoding.UTF8);
行単位で読み込む場合も文字コードを指定できます。
foreach (string line in File.ReadLines("sample.txt",Encoding.UTF8)){Console.WriteLine(line);}StreamReaderでは、コンストラクターの第2引数へ指定します。
using var reader = new StreamReader("sample.txt",Encoding.UTF8);string content = reader.ReadToEnd();
7-2. Shift_JISのファイルを読み込む
Shift_JISを扱う場合は、コードページのエンコーディングプロバイダーを登録してから、Encoding.GetEncodingを呼び出します。
using System.IO;using System.Text;Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding shiftJis = Encoding.GetEncoding("shift_jis");
string content = File.ReadAllText("sample-sjis.txt",shiftJis);
Console.WriteLine(content);
コードページ番号を指定する方法もあります。
Encoding shiftJis = Encoding.GetEncoding(932);プロジェクトの構成によっては、System.Text.Encoding.CodePagesへの参照追加が必要です。
7-3. Encodingを使った文字コード指定
Encodingクラスは、文字列とバイト列の変換規則を表します。ファイルから読み取ったバイトを文字列へ変換するときも、適切なエンコーディングが必要です。
代表的な指定例は次のとおりです。
Encoding utf8 = Encoding.UTF8;Encoding unicode = Encoding.Unicode;Encoding bigEndianUnicode = Encoding.BigEndianUnicode;Encoding utf32 = Encoding.UTF32;指定した文字コードで行単位に読み込むこともできます。
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);Encoding shiftJis = Encoding.GetEncoding(932);
foreach (string line in File.ReadLines("sample-sjis.txt",shiftJis)){Console.WriteLine(line);}
7-4. 文字化けが起きる原因と対処法
文字化けの主な原因は、ファイル作成時の文字コードと、読み込み時に指定した文字コードが一致していないことです。
例えば、Shift_JISで保存されたファイルをUTF-8として読み込むと、日本語が正しく表示されない可能性があります。
対処方法は次のとおりです。
ファイルを作成したシステムの文字コードを確認する
テキストエディターで文字コードを確認する
読み込み時に
Encodingを明示する入出力の文字コードをUTF-8へ統一する
不正なバイトを検出できるエンコーディングを使用する
文字コードの誤りを検出したい場合は、例外フォールバックを設定できます。
var utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false,throwOnInvalidBytes: true);try{string content = File.ReadAllText("sample.txt",utf8);
Console.WriteLine(content);
}catch (DecoderFallbackException ex){Console.WriteLine($"UTF-8として読み込めません: {ex.Message}");}
7-5. .NETでShift_JISを扱う際の注意点
現行の.NET環境でShift_JISなどのコードページを使用する場合は、次の登録処理が必要になることがあります。
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);プロバイダーを登録すると、そのプロバイダーが対応する文字コードをEncoding.GetEncodingで取得できるようになります。
登録後にShift_JISを取得します。
Encoding shiftJis = Encoding.GetEncoding("shift_jis");この登録は、通常、アプリケーション起動時に1回実行すれば十分です。
using System.Text;Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// 以降の処理でShift_JISを利用する
新しくシステムを設計する場合は、特別な要件がなければUTF-8への統一を検討すると、OSや実行環境の違いによる問題を減らせます。
8. 非同期でファイルを読み込む方法
8-1. File.ReadAllTextAsyncで非同期読み込みする
File.ReadAllTextAsyncは、ファイル全体を非同期で読み込んで文字列として返します。
string content = await File.ReadAllTextAsync("sample.txt");Console.WriteLine(content);
文字コードも指定できます。
using System.Text;string content = await File.ReadAllTextAsync("sample.txt",Encoding.UTF8);
このメソッドは、テキストファイルを非同期で開き、全内容を読み取ったあと、ファイルを閉じます。
8-2. ReadAllLinesAsyncの使い方
File.ReadAllLinesAsyncを使うと、すべての行を非同期で読み込み、string[]として取得できます。
string[] lines = await File.ReadAllLinesAsync("sample.txt");foreach (string line in lines){Console.WriteLine(line);}
文字コードを指定することも可能です。
string[] lines = await File.ReadAllLinesAsync("sample.txt",Encoding.UTF8);ReadAllLinesAsyncは全行を配列として返すため、非同期であっても、読み込み後のメモリ使用量はファイルサイズに応じて増えます。
8-3. async/awaitを使ったサンプルコード
非同期メソッドとしてまとめる場合は、戻り値をTaskまたはTask<T>にします。
using System;using System.IO;using System.Threading.Tasks;internal class Program{private static async Task Main(){string content = await LoadFileAsync("sample.txt");
Console.WriteLine(content);}private static async Task<string> LoadFileAsync(string path){return await File.ReadAllTextAsync(path);}
}
キャンセルに対応する場合は、CancellationTokenを渡します。
using System.Threading;static async Task<string> LoadFileAsync(string path,CancellationToken cancellationToken){return await File.ReadAllTextAsync(path,cancellationToken);}
呼び出し側では、キャンセルトークンを用意します。
using var cancellationTokenSource =new CancellationTokenSource();string content = await LoadFileAsync("sample.txt",cancellationTokenSource.Token);
8-4. 非同期読み込みが向いているケース
非同期読み込みは、次のようなアプリケーションに向いています。
デスクトップUIを操作可能な状態に保ちたい
Webアプリで処理スレッドの長時間ブロックを避けたい
複数のI/O処理を効率よく待機したい
ネットワークドライブや低速ストレージを利用する
ファイルI/O中にほかの処理を進めたい
非同期ファイルアクセスでは、コールバックを直接組み立てなくても、asyncとawaitを使って処理を記述できます。
8-5. 同期処理と非同期処理の使い分け
小さなファイルをコンソールアプリの起動時に1回だけ読む程度なら、同期処理でも十分な場合があります。
string content = File.ReadAllText("settings.txt");UIアプリやWebアプリなど、読み込み中も応答性を維持したい場合は、非同期処理を検討します。
string content = await File.ReadAllTextAsync("settings.txt");ただし、ReadAllTextAsyncは待機方法が非同期になるだけで、ファイル全体を文字列として保持する点はReadAllTextと同じです。大容量ファイルのメモリ使用量を抑えたい場合は、StreamReader.ReadLineAsyncなどを使って順番に読み込みます。
using var reader = new StreamReader("large-log.txt");string? line;
while ((line = await reader.ReadLineAsync()) is not null){Console.WriteLine(line);}
9. ファイル読み込み時によくあるエラーと対処法
9-1. FileNotFoundException:ファイルが見つからない
指定したファイルが存在しない場合、FileNotFoundExceptionが発生することがあります。
try{string content = File.ReadAllText("not-found.txt");}catch (FileNotFoundException ex){Console.WriteLine($"ファイルが見つかりません: {ex.FileName}");}主な確認事項は次のとおりです。
ファイル名のスペル
拡張子
相対パスの基準
ビルド出力先へのコピー設定
大文字と小文字の違い
実際に組み立てられたパス
デバッグ時は、対象パスを出力すると原因を特定しやすくなります。
Console.WriteLine(Path.GetFullPath(path));9-2. UnauthorizedAccessException:アクセス権限がない
ファイルやフォルダへのアクセス権限がない場合は、UnauthorizedAccessExceptionが発生します。
try{string content = File.ReadAllText(path);}catch (UnauthorizedAccessException ex){Console.WriteLine($"アクセス権限がありません: {ex.Message}");}ファイルではなくフォルダのパスをReadAllTextへ渡した場合も、この例外が発生することがあります。
次の点を確認しましょう。
読み取り権限が付与されているか
実行ユーザーが正しいか
保護されたシステムフォルダではないか
指定したパスがファイルを指しているか
9-3. IOException:ファイルが使用中の場合
ファイルが別のプロセスによって排他的に開かれている場合や、入出力処理に問題が発生した場合は、IOExceptionが発生することがあります。
try{string content = File.ReadAllText(path);}catch (IOException ex){Console.WriteLine($"ファイルの読み込みに失敗しました: {ex.Message}");}ログファイルなど、ほかのアプリケーションが書き込み中のファイルを読みたい場合は、FileStreamで共有モードを指定する方法があります。
using var stream = new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.ReadWrite);using var reader = new StreamReader(stream);
string content = reader.ReadToEnd();
ただし、書き込み途中の内容を読み込む可能性があるため、取得したデータが完全な状態とは限りません。
9-4. DirectoryNotFoundException:フォルダが存在しない
ファイル名が正しくても、途中のフォルダが存在しなければDirectoryNotFoundExceptionが発生します。
try{string content = File.ReadAllText(@"C:\not-found\sample.txt");}catch (DirectoryNotFoundException ex){Console.WriteLine($"フォルダが見つかりません: {ex.Message}");}親フォルダの存在を確認する場合は、Directory.Existsを使用できます。
string? directory = Path.GetDirectoryName(path);if (string.IsNullOrEmpty(directory) ||!Directory.Exists(directory)){Console.WriteLine("対象フォルダが存在しません。");}
9-5. try-catchで安全にエラー処理する方法
複数の例外を処理する場合は、具体的な例外を先に記述します。
try{string content = File.ReadAllText(path,Encoding.UTF8);Console.WriteLine(content);
}catch (FileNotFoundException ex){Console.WriteLine($"ファイルが見つかりません: {ex.FileName}");}catch (DirectoryNotFoundException ex){Console.WriteLine($"フォルダが見つかりません: {ex.Message}");}catch (UnauthorizedAccessException ex){Console.WriteLine($"アクセス権限がありません: {ex.Message}");}catch (IOException ex){Console.WriteLine($"入出力エラーが発生しました: {ex.Message}");}
FileNotFoundExceptionやDirectoryNotFoundExceptionはIOExceptionの派生型であるため、IOExceptionを先に書くと、個別のcatchへ到達できなくなります。
ユーザー向けメッセージには必要な情報だけを表示し、詳細な例外情報はログへ記録する設計が一般的です。
10. 読み込み方法別の比較と選び方
10-1. 小さなファイルならReadAllText
設定ファイルやテンプレートなど、サイズが小さく、内容全体を使用する場合はReadAllTextが適しています。
string template = File.ReadAllText("template.txt");コードが簡潔で、ファイルのオープンとクローズもメソッド内部で処理されます。
10-2. 行ごとに処理するならReadLines
CSV、ログ、一覧データなどを1行ずつ処理する場合は、ReadLinesが使いやすい方法です。
foreach (string line in File.ReadLines("data.txt")){ProcessLine(line);}全件を配列に格納しないため、ファイルサイズが大きい場合にも適しています。
10-3. 細かく制御したいならStreamReader
読み込み途中で状態を管理したい場合や、FileStreamの設定を変更したい場合は、StreamReaderを選びます。
using var reader = new StreamReader("data.txt",Encoding.UTF8);string? line;
while ((line = reader.ReadLine()) is not null){if (ShouldStop(line)){break;}
ProcessLine(line);
}
文字コード、共有方法、非同期処理などを組み合わせやすい点が特徴です。
10-4. UIアプリやWebアプリでは非同期読み込みを検討する
ファイルI/Oの完了を待つ間に画面やサーバー処理をブロックしたくない場合は、非同期メソッドを検討します。
string content = await File.ReadAllTextAsync("data.txt");大容量ファイルを非同期かつ行単位で処理する場合は、ReadLineAsyncを使用できます。
using var reader = new StreamReader("large-data.txt");string? line;
while ((line = await reader.ReadLineAsync()) is not null){ProcessLine(line);}
10-5. 用途別おすすめ読み込み方法一覧
| 用途 | おすすめの方法 |
| 小さなtxtファイルを全文取得 | File.ReadAllText |
| 全行を配列として操作 | File.ReadAllLines |
| 大容量ファイルを行単位で処理 | File.ReadLines |
| 読み込みを細かく制御 | StreamReader |
| ファイル全体を非同期取得 | File.ReadAllTextAsync |
| 全行を非同期で配列化 | File.ReadAllLinesAsync |
| 大容量ファイルを非同期で処理 | StreamReader.ReadLineAsync |
| 特定の文字コードで読み込み | Encodingを指定 |
| 書き込み中のログを参照 | 共有モードを設定したFileStreamとStreamReader |
迷った場合は、まず次の3点を確認します。
ファイル全体をメモリへ格納して問題ないか
全文が必要か、1行ずつ処理できるか
読み込み中に処理をブロックしても問題ないか
この判断によって、候補を絞り込めます。
11. C#のファイル読み込みに関するよくある質問
11-1. C#でtxtファイルを読み込むには?
txtファイル全体を読み込むだけなら、File.ReadAllTextを使用します。
string content = File.ReadAllText("sample.txt");Console.WriteLine(content);
日本語の文字コードを明示したい場合は、Encoding.UTF8などを指定します。
string content = File.ReadAllText("sample.txt",Encoding.UTF8);11-2. C#でファイルを1行ずつ読み込むには?
簡潔に書くなら、File.ReadLinesとforeachを使用します。
foreach (string line in File.ReadLines("sample.txt")){Console.WriteLine(line);}読み込み処理を細かく制御する場合は、StreamReader.ReadLineを使用します。
using var reader = new StreamReader("sample.txt");string? line;
while ((line = reader.ReadLine()) is not null){Console.WriteLine(line);}
11-3. C#でファイル全体を文字列として読み込むには?
File.ReadAllTextを使用すると、ファイル全体を1つの文字列として取得できます。
string text = File.ReadAllText("sample.txt");非同期で取得する場合は、File.ReadAllTextAsyncを使用します。
string text = await File.ReadAllTextAsync("sample.txt");11-4. C#で文字化けせずにファイルを読み込むには?
ファイル保存時の文字コードを確認し、同じ文字コードを読み込み時に指定します。
UTF-8の場合は次のとおりです。
string content = File.ReadAllText("sample.txt",Encoding.UTF8);Shift_JISの場合は、コードページプロバイダーを登録してから読み込みます。
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);Encoding shiftJis = Encoding.GetEncoding(932);
string content = File.ReadAllText("sample.txt",shiftJis);
文字コードが不明なファイルを常に正確に自動判定することは困難です。可能であれば、ファイル仕様として文字コードを決めておきましょう。
11-5. 大容量ファイルを読み込む場合はどの方法がよい?
大容量ファイルでは、ファイル全体を読み込むReadAllTextやReadAllLinesより、File.ReadLinesまたはStreamReader.ReadLineが適しています。
foreach (string line in File.ReadLines("large-file.txt")){ProcessLine(line);}非同期で1行ずつ処理する場合は、ReadLineAsyncを使用できます。
using var reader = new StreamReader("large-file.txt");string? line;
while ((line = await reader.ReadLineAsync()) is not null){ProcessLine(line);}
処理済みの行をリストなどへ保存し続けると、行単位で読み込んでいてもメモリ使用量が増えます。大容量ファイルでは、読み込んだ行をその場で処理し、不要になったデータを保持しないことが重要です。
まとめ
C#でファイルを読み込む方法は、ファイルサイズや処理内容に応じて使い分けます。
ファイル全体を文字列として取得するならFile.ReadAllText、全行を配列として扱うならFile.ReadAllLinesが便利です。CSVやログファイルを1行ずつ処理する場合や、大容量ファイルを扱う場合は、File.ReadLinesが適しています。
読み込み処理を細かく制御したい場合は、StreamReaderを利用します。UIアプリやWebアプリで処理のブロックを避けたい場合は、ReadAllTextAsyncやReadLineAsyncなどの非同期メソッドも検討しましょう。
また、文字化けを防ぐには、ファイルの文字コードと読み込み時のEncodingを一致させる必要があります。ファイルパスについては、相対パスの基準を確認し、必要に応じてPath.CombineやAppContext.BaseDirectoryを活用してください。
適切な読み込み方法を選び、文字コード、例外処理、メモリ使用量まで考慮することで、安全で効率的なファイル処理を実装できます。

