【初心者向け】C#でのファイル操作を完全ガイド|基本から実践まで

C#

C#でアプリケーションを開発していると、必ずといっていいほど登場するのが「ファイル操作」です。テキストファイルの読み書き、ファイルの移動や削除、ディレクトリの操作など、用途はさまざま。

しかし、初めて触れる方にとっては、どのクラスやメソッドを使えばよいのか迷ってしまうこともあるでしょう。

この記事では、C#でのファイル操作を基礎から丁寧に解説し、実際のコード例も交えて、すぐに使える知識をお届けします。

スポンサーリンク

C#で使う主なファイル操作クラスとは?

基本的なクラス

C#では、主に System.IO 名前空間の中にある以下のクラスを使ってファイル操作を行います。

主なクラス:

  • File:ファイルの作成・削除・コピーなどの基本操作
  • FileInfo:ファイルの詳細情報やインスタンスベースの操作
  • StreamReader / StreamWriter:テキストファイルの読み書き
  • Directory / DirectoryInfo:ディレクトリの操作

どのクラスをいつ使う?

Fileクラス:

  • 簡単なファイル操作に便利
  • 静的メソッドで使いやすい
  • 少ないコード量で完結
  • 基本的な動作のほとんどをカバー

FileInfoクラス:

  • ファイルの詳しい情報が必要なとき
  • 同じファイルに対して複数の操作をしたいとき
  • ファイルサイズや更新日付の取得
  • オブジェクトとして扱いたいとき

基本例

using System.IO;

// 簡単な書き込みと読み込み
File.WriteAllText("sample.txt", "こんにちは、世界!");
string content = File.ReadAllText("sample.txt");
Console.WriteLine(content);

このコードの流れ:

  1. File.WriteAllText で「sample.txt」に文字を書き込む
  2. File.ReadAllText でそのファイルから文字を読み込む
  3. コンソールに読み込んだ文字を表示

承知しました。続きを以下に表示いたします。


使う前の準備

using System;
using System.IO;

namespace FileExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // ここにファイル操作のコードを書く
        }
    }
}

まとめ: 基本的なクラスを押さえておけば、ほとんどのファイル操作に対応できます。

次は、実際の読み書き処理について詳しく見ていきましょう。


テキストファイルを読み書きする方法

基本的な読み書き

文字列データをファイルに保存したり、逆に読み込んだりするのが「テキストファイルの操作」です。

ここでは最も基本的な読み書き処理を紹介します。

基本の書き込みと読み込み:

// 書き込み
File.WriteAllText("data.txt", "保存する内容");

// 読み込み
string data = File.ReadAllText("data.txt");
Console.WriteLine(data); // 「保存する内容」が表示される

なぜこれで動作するの?

  1. WriteAllText がファイルを自動的に作成する
  2. 一度にすべての文字を書き込む
  3. ReadAllText がファイル全体を読み込む
  4. 読み込んだ文字列を戻してくれる

複数行の扱い

// 複数行書き込み
string[] lines = { "行1", "行2", "行3" };
File.WriteAllLines("lines.txt", lines);

// 複数行読み込み
string[] readLines = File.ReadAllLines("lines.txt");
foreach (var line in readLines) 
{
    Console.WriteLine(line);
}

ファイルの中身:

行1  
行2  
行3

追記書き込み(AppendAllText)

// はじめの書き込み
File.WriteAllText("log.txt", "ログ開始\n");

// 追記書き込み
File.AppendAllText("log.txt", "新しいログ\n");
File.AppendAllText("log.txt", "さらにログ\n");

// 結果表示
string allContent = File.ReadAllText("log.txt");
Console.WriteLine(allContent);

結果のファイル:

ログ開始  
新しいログ  
さらにログ

文字コードの指定

using System.Text;

// UTF-8で書き込み
File.WriteAllText("utf8.txt", "日本語のテキスト", Encoding.UTF8);

// UTF-8で読み込み
string content = File.ReadAllText("utf8.txt", Encoding.UTF8);

なぜ文字コードが大切?

  • 日本語を正しく表示するため
  • 文字化けを防ぐため
  • 別のアプリでも正しく表示されるため

まとめ: テキストファイルは基本ですが、実務ではファイルの存在チェックや例外処理も重要です。

次章ではその点を見ていきます。


承知しました。次のセクションを表示いたします。


ファイルの存在確認と例外処理

なぜ確認が必要?

操作対象のファイルが存在しない場合や、他のプロセスによりロックされている場合には、エラーが発生します。

そのため、事前の存在確認と適切なエラーハンドリングが重要です。

存在確認の基本

if (File.Exists("check.txt")) 
{
    Console.WriteLine("ファイルは存在します");

    // ファイルがあるときだけ読み込み
    string content = File.ReadAllText("check.txt");
    Console.WriteLine($"内容: {content}");
} 
else 
{
    Console.WriteLine("ファイルが見つかりません");

    // ファイルがないときは作成
    File.WriteAllText("check.txt", "新しいファイルです");
    Console.WriteLine("新しいファイルを作成しました");
}

例外処理の基本

try 
{
    string content = File.ReadAllText("no-file.txt");
    Console.WriteLine(content);
} 
catch (FileNotFoundException ex) 
{
    Console.WriteLine($"ファイルが見つかりません: {ex.Message}");
} 
catch (IOException ex) 
{
    Console.WriteLine($"ファイル読み込みエラー: {ex.Message}");
} 
catch (Exception ex) 
{
    Console.WriteLine($"予想外のエラー: {ex.Message}");
}

よくあるエラーと対処

FileNotFoundException:

  • ファイルが見つからない
  • → 先に File.Exists で確認する

IOException:

  • ファイルが別のプロセスで使われている
  • → しばらく待ってから再試行

UnauthorizedAccessException:

  • アクセス権限がない
  • → 権限を確認するか別の場所を使う

安全なファイル操作の例

public static bool SafeWriteFile(string filePath, string content)
{
    try
    {
        // ディレクトリがなければ作成
        string directory = Path.GetDirectoryName(filePath);
        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }

        // ファイル書き込み
        File.WriteAllText(filePath, content);
        Console.WriteLine($"ファイルの保存が完了しました: {filePath}");
        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"ファイル保存エラー: {ex.Message}");
        return false;
    }
}

// 使い方
bool success = SafeWriteFile("logs/today.txt", "今日のログ");

まとめ: エラー対策をすることで、より堅牢なアプリケーションになります。

次は、ディレクトリの作成やファイルの移動・削除について見てみましょう。


承知しました。それでは「ディレクトリやファイルの操作」セクションの内容を表示いたします。


ディレクトリやファイルの操作

ディレクトリの操作

アプリ開発では、フォルダ(ディレクトリ)の作成や、ファイルの移動・削除などもよく使われます。これらも System.IO で対応可能です。

ディレクトリの作成:

// 単一ディレクトリ
Directory.CreateDirectory("新しいフォルダ");

// 複数階層のディレクトリ
Directory.CreateDirectory("親/子/孫");

// 存在確認
if (Directory.Exists("新しいフォルダ"))
{
    Console.WriteLine("フォルダがあります");
}

ファイルの移動とコピー

// ファイル移動(場所を変える)
File.Move("sample.txt", "新しいフォルダ/sample.txt");

// ファイルコピー(複製を作る)
File.Copy("sample.txt", "sample_copy.txt");

// 上書きコピー
File.Copy("sample.txt", "sample_copy.txt", true); // true で上書き

ファイルの削除

// 安全な削除
if (File.Exists("不要なファイル.txt"))
{
    File.Delete("不要なファイル.txt");
    Console.WriteLine("ファイルを削除しました");
}
else
{
    Console.WriteLine("削除対象のファイルがありません");
}

ディレクトリの中身一覧

// ファイル一覧
string[] files = Directory.GetFiles("フォルダ名");
foreach (string file in files)
{
    Console.WriteLine($"ファイル: {Path.GetFileName(file)}");
}

// ディレクトリ一覧
string[] directories = Directory.GetDirectories("フォルダ名");
foreach (string dir in directories)
{
    Console.WriteLine($"フォルダ: {Path.GetFileName(dir)}");
}

パスの扱い

// パスを結合(OSに依存しない)
string filePath = Path.Combine("フォルダ", "サブフォルダ", "ファイル.txt");

// ファイル名だけを取り出す
string fileName = Path.GetFileName(@"C:\フォルダ\ファイル.txt"); // "ファイル.txt"

// 拡張子を取り出す
string extension = Path.GetExtension("ファイル.txt"); // ".txt"

// ディレクトリを取り出す
string directory = Path.GetDirectoryName(@"C:\フォルダ\ファイル.txt"); // "C:\フォルダ"

ディレクトリの削除

// 空のディレクトリを削除
Directory.Delete("空のフォルダ");

// 中身があってもまとめて削除
Directory.Delete("フォルダと中身", true); // true で再帰的削除

まとめ: これらの操作をマスターすれば、より柔軟なファイル処理が可能になります。

最後に、より実践的な使い方として、ログファイルの自動生成について紹介します。

承知しました。それでは「実践編:ログファイルの自動生成」セクションを表示いたします。


実践編:ログファイルの自動生成

なぜログが大切?

アプリケーションにおいて、エラーや処理内容をログとして記録することは非常に重要です。

ここでは、日付ごとのログファイルを作成し、追記していく方法を紹介します。


基本的なログシステム

public class SimpleLogger
{
    private string logDirectory;

    public SimpleLogger()
    {
        logDirectory = "logs";
        Directory.CreateDirectory(logDirectory); // ログフォルダがなければ作成
    }

    public void WriteLog(string message)
    {
        // 日付ごとのファイル名
        string logFile = Path.Combine(logDirectory, $"{DateTime.Now:yyyyMMdd}.log");

        // ログエントリの作成
        string logEntry = $"{DateTime.Now:HH:mm:ss} - {message}";

        // ファイルに追記
        File.AppendAllText(logFile, logEntry + Environment.NewLine);
    }
}

// 使い方
SimpleLogger logger = new SimpleLogger();
logger.WriteLog("アプリケーション開始");
logger.WriteLog("ユーザーログイン完了");
logger.WriteLog("ファイル処理完了");

高機能ログシステム

public class AdvancedLogger
{
    private string logDirectory;

    public AdvancedLogger(string directory = "logs")
    {
        logDirectory = directory;
        Directory.CreateDirectory(logDirectory);
    }

    public void WriteLog(string level, string message)
    {
        try
        {
            string logFile = Path.Combine(logDirectory, $"{DateTime.Now:yyyyMMdd}.log");
            string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";

            File.AppendAllText(logFile, logEntry + Environment.NewLine);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"ログ処理エラー: {ex.Message}");
        }
    }

    public void Info(string message) => WriteLog("INFO", message);
    public void Warning(string message) => WriteLog("WARNING", message);
    public void Error(string message) => WriteLog("ERROR", message);

    // 古いログファイルの削除
    public void CleanOldLogs(int keepDays = 30)
    {
        string[] logFiles = Directory.GetFiles(logDirectory, "*.log");
        DateTime cutoff = DateTime.Now.AddDays(-keepDays);

        foreach (string file in logFiles)
        {
            FileInfo fileInfo = new FileInfo(file);
            if (fileInfo.CreationTime < cutoff)
            {
                fileInfo.Delete();
                Console.WriteLine($"古いログを削除: {fileInfo.Name}");
            }
        }
    }
}

// 使い方
AdvancedLogger logger = new AdvancedLogger();
logger.Info("アプリケーション開始");
logger.Warning("設定ファイルが見つかりません");
logger.Error("データベース接続エラー");

// 30日より古いログを削除
logger.CleanOldLogs(30);

コンフィグファイルの読み込み

public class ConfigReader
{
    public Dictionary<string, string> ReadConfig(string configFile)
    {
        var config = new Dictionary<string, string>();

        if (!File.Exists(configFile))
        {
            // デフォルトコンフィグを作成
            CreateDefaultConfig(configFile);
        }

        string[] lines = File.ReadAllLines(configFile);
        foreach (string line in lines)
        {
            if (line.Contains("=") && !line.StartsWith("#"))
            {
                string[] parts = line.Split('=', 2);
                config[parts[0].Trim()] = parts[1].Trim();
            }
        }

        return config;
    }

    private void CreateDefaultConfig(string configFile)
    {
        string[] defaultConfig = {
            "# アプリケーション設定",
            "DatabasePath=data.db",
            "LogLevel=INFO",
            "MaxUsers=100"
        };

        File.WriteAllLines(configFile, defaultConfig);
    }
}

// 使い方
ConfigReader configReader = new ConfigReader();
var settings = configReader.ReadConfig("app.config");

Console.WriteLine($"データベースパス: {settings.GetValueOrDefault("DatabasePath", "指定なし")}");

まとめ: 日付ごとのログ管理により、アプリケーションのメンテナンス性が向上します


ファイル操作のまとめと向上のヒント

このガイドでは、C#でのファイル操作について、基本から応用まで丁寧に解説しました。

以下のポイントを押さえておきましょう。


重要なポイント

  1. System.IOの各クラスを使い分ける
    • File:基本的なファイル操作(静的)
    • Directory:フォルダ操作
    • Path:パスの結合や分解
  2. 読み書き、存在確認、例外処理を適切に行う
    • 必ず File.ExistsDirectory.Exists で存在確認
    • try-catch で堅牢なエラーハンドリング
    • 安全なコードの書き方を習慣づける
  3. 実務ではログ処理なども重要
    • アプリケーションの状態記録
    • エラー分析のための証跡
    • ユーザーの操作履歴管理など

よくある失敗と対策

失敗1:ファイルパスの間違い

// NG:固定パス
File.ReadAllText("C:\\Users\\UserName\\file.txt");

// OK:動的パス
string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "file.txt");

失敗2:例外処理をしない

// NG:エラーハンドリングなし
string content = File.ReadAllText("file.txt");

// OK:しっかりとした例外処理
try
{
    if (File.Exists("file.txt"))
    {
        string content = File.ReadAllText("file.txt");
    }
}
catch (Exception ex)
{
    Console.WriteLine($"エラー: {ex.Message}");
}

失敗3:リソースの解放忘れ

// OK:usingで自動解放
using (StreamReader reader = new StreamReader("file.txt"))
{
    string content = reader.ReadToEnd();
}

コメント

タイトルとURLをコピーしました