C# Tips | ファイル・ディレクトリ操作:ファイルサイズ取得

C sharp C#
スポンサーリンク

はじめに なぜ「ファイルサイズ取得」が業務で重要なのか

業務システムでは、「受信したファイルが想定サイズ以上かチェックする」「空ファイル(サイズ 0)をエラーとして弾く」「バックアップやログの容量を集計してディスク使用量を監視する」など、ファイルサイズを扱う場面がとても多いです。
サイズを見ずに処理すると、「中身が入っていないファイルをそのまま取り込んでしまう」「巨大ファイルを読み込んでメモリを圧迫する」といったトラブルにつながります。

C# では、System.IO.FileInfo クラスを使うことで、ファイルサイズを簡単かつ安全に取得できます。
ここでは、プログラミング初心者向けに、基本の使い方から、業務で使えるユーティリティ化、サイズの単位変換や合計サイズの計算まで、かみ砕いて解説していきます。


基本のメソッド FileInfo.Length でファイルサイズを取得する

最もシンプルなファイルサイズ取得

まずは、「特定のファイルのサイズをバイト単位で取得する」一番シンプルな例から見てみましょう。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\data\report.csv";

        FileInfo info = new FileInfo(path);

        long size = info.Length;

        Console.WriteLine($"ファイルサイズ: {size} バイト");
    }
}
C#

ここで重要なのは、サイズの型が long であることです。
ファイルサイズはかなり大きくなる可能性があるため、int ではなく 64 ビット整数の long で扱います。
FileInfo.Length は「ファイルのサイズ(バイト数)」をそのまま返してくれるプロパティです。

また、FileInfo を使うためには、using System.IO; を書いておく必要があります。
ファイル・ディレクトリ操作をするときは、まず using System.IO; と書く、というのをセットで覚えておくと楽です。

ファイルが存在しない場合の扱い

存在しないパスで new FileInfo(path) をしても、その時点では例外は出ません。
しかし、info.Length にアクセスしたタイミングで、ファイルが存在しないと FileNotFoundException が発生します。

業務コードでは、「存在チェック」と「サイズ取得」をセットで行うことが多いです。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\data\report.csv";

        if (!File.Exists(path))
        {
            Console.WriteLine("ファイルが存在しません。");
            return;
        }

        FileInfo info = new FileInfo(path);
        long size = info.Length;

        Console.WriteLine($"ファイルサイズ: {size} バイト");
    }
}
C#

このようにしておくと、「そもそもファイルがない」というケースを、サイズ取得とは別に扱えます。


実務で使えるユーティリティ化 単体ファイルのサイズ取得

安全にサイズを取得するユーティリティメソッド

毎回 File.Existsnew FileInfo を書くのは面倒なので、「安全にサイズを取得する」ユーティリティメソッドを用意しておくと便利です。

using System;
using System.IO;

public static class FileSizeUtil
{
    public static long GetFileSize(string filePath)
    {
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException($"ファイルが見つかりません: {filePath}", filePath);
        }

        FileInfo info = new FileInfo(filePath);
        return info.Length;
    }
}
C#

使い方の例は次の通りです。

class Program
{
    static void Main()
    {
        string path = @"C:\data\report.csv";

        try
        {
            long size = FileSizeUtil.GetFileSize(path);
            Console.WriteLine($"ファイルサイズ: {size} バイト");
        }
        catch (FileNotFoundException ex)
        {
            Console.WriteLine("エラー: " + ex.Message);
        }
    }
}
C#

ここでのポイントは、「存在しない場合は 0 を返す」のではなく、「例外として扱う」設計にしていることです。
業務によっては、「ファイルがないのは異常」とみなすことが多く、その場合は例外で止めたほうがバグに気づきやすくなります。

「存在しないなら 0」を返すバージョン

一方で、「存在しなければサイズ 0 として扱いたい」というケースもあります。
その場合は、戻り値で表現するユーティリティを用意します。

public static class FileSizeUtil
{
    public static long GetFileSizeOrZero(string filePath)
    {
        if (!File.Exists(filePath))
        {
            return 0;
        }

        FileInfo info = new FileInfo(filePath);
        return info.Length;
    }
}
C#

このように、「例外で止めるか」「0 で返すか」をメソッドごとに分けておくと、呼び出し側の意図が明確になります。


サイズの単位変換 バイトから KB・MB・GB へ

バイトのままだと人間には分かりにくい

FileInfo.Length はバイト単位ですが、人間が見るには「何 MB くらいか」のほうが直感的です。
そこで、バイト数を KB・MB・GB に変換するユーティリティを用意しておくと便利です。

一般的には、次のような換算を使います。

1 KB = 1024 バイト
1 MB = 1024 KB = 1024 × 1024 バイト
1 GB = 1024 MB = 1024 × 1024 × 1024 バイト

シンプルな変換メソッド

まずは、「バイト数から MB を求める」シンプルな例です。

public static class FileSizeUtil
{
    public static double ToMegaBytes(long bytes)
    {
        return bytes / 1024.0 / 1024.0;
    }
}
C#

使い方の例は次の通りです。

class Program
{
    static void Main()
    {
        string path = @"C:\data\bigfile.bin";

        long size = FileSizeUtil.GetFileSize(path);
        double mb  = FileSizeUtil.ToMegaBytes(size);

        Console.WriteLine($"ファイルサイズ: {size} バイト ({mb:F2} MB)");
    }
}
C#

ここでのポイントは、「整数同士で割ると小数点以下が切り捨てられてしまう」ので、1024.0 のように double で割っていることです。
{mb:F2} は「小数点以下 2 桁まで表示」という意味です。

自動で単位を選んで文字列にする

もう少し実務寄りにするなら、「サイズに応じて B / KB / MB / GB を自動で選んで文字列にする」メソッドもよく使われます。

public static class FileSizeUtil
{
    public static string FormatSize(long bytes)
    {
        const double KB = 1024.0;
        const double MB = KB * 1024.0;
        const double GB = MB * 1024.0;

        if (bytes < KB)
        {
            return $"{bytes} B";
        }
        else if (bytes < MB)
        {
            double value = bytes / KB;
            return $"{value:F2} KB";
        }
        else if (bytes < GB)
        {
            double value = bytes / MB;
            return $"{value:F2} MB";
        }
        else
        {
            double value = bytes / GB;
            return $"{value:F2} GB";
        }
    }
}
C#

使い方の例は次の通りです。

class Program
{
    static void Main()
    {
        string path = @"C:\data\archive.zip";

        long size = FileSizeUtil.GetFileSize(path);
        string formatted = FileSizeUtil.FormatSize(size);

        Console.WriteLine($"ファイルサイズ: {formatted}");
    }
}
C#

このようにしておくと、ログや画面表示で「人間にとって読みやすいサイズ」を簡単に出せます。


フォルダ内のファイルサイズ合計を求める

指定フォルダ直下の合計サイズ

業務では、「このフォルダがどれくらいディスクを使っているか」を知りたいことがよくあります。
その場合は、フォルダ内のファイルサイズを合計します。

using System;
using System.IO;

public static class DirectorySizeUtil
{
    public static long GetDirectorySize(string directoryPath)
    {
        if (!Directory.Exists(directoryPath))
        {
            throw new DirectoryNotFoundException($"ディレクトリが見つかりません: {directoryPath}");
        }

        long total = 0;

        string[] files = Directory.GetFiles(directoryPath);

        foreach (string filePath in files)
        {
            FileInfo info = new FileInfo(filePath);
            total += info.Length;
        }

        return total;
    }
}
C#

使い方の例は次の通りです。

class Program
{
    static void Main()
    {
        string dir = @"C:\logs\app";

        long totalBytes = DirectorySizeUtil.GetDirectorySize(dir);
        string formatted = FileSizeUtil.FormatSize(totalBytes);

        Console.WriteLine($"ディレクトリの合計サイズ: {formatted}");
    }
}
C#

ここでのポイントは、「合計サイズも long で持つ」ことです。
多数のファイルを足し合わせると、すぐに大きな値になるためです。

サブフォルダも含めた再帰的な合計サイズ

さらに、「サブフォルダも含めてフォルダ全体のサイズを知りたい」場合は、再帰的にディレクトリをたどります。

public static class DirectorySizeUtil
{
    public static long GetDirectorySizeRecursive(string directoryPath)
    {
        if (!Directory.Exists(directoryPath))
        {
            throw new DirectoryNotFoundException($"ディレクトリが見つかりません: {directoryPath}");
        }

        long total = 0;
        AddDirectorySize(directoryPath, ref total);
        return total;
    }

    private static void AddDirectorySize(string directoryPath, ref long total)
    {
        foreach (string filePath in Directory.GetFiles(directoryPath))
        {
            FileInfo info = new FileInfo(filePath);
            total += info.Length;
        }

        foreach (string subDir in Directory.GetDirectories(directoryPath))
        {
            AddDirectorySize(subDir, ref total);
        }
    }
}
C#

このようにしておくと、「ログフォルダ全体で何 GB 使っているか」「バックアップフォルダがディスクを圧迫していないか」といった監視に使えます。


実務での典型パターンと注意点

「サイズ 0 のファイルをエラー扱いする」チェック

よくある業務要件として、「空ファイルはエラーとして扱う」というものがあります。
たとえば、外部システムから受信した CSV がサイズ 0 だった場合、「データが来ていない」と判断したいケースです。

その場合のコードイメージは次の通りです。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\import\sales.csv";

        long size = FileSizeUtil.GetFileSize(path);

        if (size == 0)
        {
            Console.WriteLine("エラー: ファイルサイズが 0 です。");
            return;
        }

        Console.WriteLine("ファイルサイズは正常です。処理を続行します。");
    }
}
C#

このように、「サイズチェックを最初に行う」ことで、無駄なパース処理や後続エラーを防げます。

「想定以上に大きいファイルを拒否する」ガード

逆に、「あまりに大きいファイルは処理しない」というガードも重要です。
たとえば、「10 MB を超える CSV は受け付けない」といったルールです。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\import\large.csv";

        long size = FileSizeUtil.GetFileSize(path);
        double mb = FileSizeUtil.ToMegaBytes(size);

        if (mb > 10.0)
        {
            Console.WriteLine($"エラー: ファイルが大きすぎます ({mb:F2} MB)。");
            return;
        }

        Console.WriteLine("サイズは許容範囲内です。処理を続行します。");
    }
}
C#

こうしたガードを入れておくことで、「想定外の巨大ファイルでメモリや処理時間が爆発する」事故を防げます。


例外とエラー処理を意識したファイルサイズ取得

どんな例外が起こり得るか

ファイルサイズ取得では、次のような理由で例外が発生する可能性があります。
ファイルが存在しない、権限がなくてアクセスできない、別プロセスがロックしている、パスが不正または長すぎる、などです。

呼び出し側での例外処理の例を見てみます。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\data\report.csv";

        try
        {
            long size = FileSizeUtil.GetFileSize(path);
            string formatted = FileSizeUtil.FormatSize(size);

            Console.WriteLine($"ファイルサイズ: {formatted}");
        }
        catch (FileNotFoundException ex)
        {
            Console.WriteLine("ファイルが見つかりません: " + ex.Message);
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine("権限エラーが発生しました: " + ex.Message);
        }
        catch (IOException ex)
        {
            Console.WriteLine("入出力エラーが発生しました: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("想定外のエラーが発生しました: " + ex.Message);
        }
    }
}
C#

実務では、これらのメッセージをログに残しておくことで、「どのファイルのサイズ取得に、どんな理由で失敗したか」を後から追跡できます。


まとめ 実務で使えるファイルサイズ取得ユーティリティの考え方

ファイルサイズ取得は、一見シンプルですが、「空ファイルの検知」「巨大ファイルのガード」「ディスク使用量の監視」など、業務システムの安定運用を支える重要な要素です。
だからこそ、「ただ Length を読む」だけで終わらせず、ユーティリティとして整理しておく価値があります。

FileInfo.Length を使って、サイズを long で正しく扱うこと。
存在チェックを含めたユーティリティ(例外を投げる版と、0 を返す版)を用意し、用途に応じて使い分けること。
バイトから KB・MB・GB への変換や、人間向けのフォーマット表示をユーティリティ化しておき、ログや画面で読みやすくすること。
フォルダ単位の合計サイズ取得や、再帰的なディレクトリサイズ計算を用意して、ログ・バックアップ・一時領域の容量管理に活かすこと。
サイズ 0 のファイルや、想定以上に大きいファイルを検知して、処理前に弾くガードを入れておくこと。

ここまで押さえておけば、「サイズを見ずに処理してしまったせいで起きるトラブル」をかなり減らせます。

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