C# Tips | ファイル・ディレクトリ操作:一時ファイル作成

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

はじめに 一時ファイルは「使い捨ての作業机」

業務システムを書いていると、「ちょっとだけデータを置いておきたい」場面がよく出てきます。
たとえば、大きなファイルを分割して処理するときの中間結果、ダウンロード中の一時データ、圧縮前の展開ファイルなどです。

こういうときに、いきなり本番の保存先に書くのではなく、「一時ファイル」に書いておいて、処理が成功したら本番に移動、失敗したら捨てる、という設計にすると安全性がぐっと上がります。
C# には、この「一時ファイル」を簡単に作るための仕組みが標準で用意されています。

ここでは、初心者向けに「一時ファイルとは何か」「どう作るか」「どう片付けるか」を、実務で使えるユーティリティという視点で丁寧に解説していきます。


一時ファイルの基本 Path.GetTempFileName と Path.GetTempPath

一時フォルダの場所を知る Path.GetTempPath

まず、「一時ファイルをどこに作るか」という話からです。
C# では、Path.GetTempPath() を呼ぶと、OS が用意している「一時フォルダ」のパスを取得できます。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string tempDir = Path.GetTempPath();
        Console.WriteLine("一時フォルダ: " + tempDir);
    }
}
C#

Windows なら、だいたい C:\Users\ユーザー名\AppData\Local\Temp\ のような場所が返ってきます。
「一時ファイルはここに作る」というのが基本ルールです。自分で勝手に C ドライブ直下などに作るより、OS 標準の場所を使ったほうが安全で、クリーンアップの対象にもなりやすいです。

一時ファイルを作る Path.GetTempFileName

実際に一時ファイルを作るには、Path.GetTempFileName() を使います。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string tempFilePath = Path.GetTempFileName();

        Console.WriteLine("作成された一時ファイル: " + tempFilePath);
    }
}
C#

ここで重要なのは、このメソッドを呼んだ瞬間に「ディスク上に 0 バイトの空ファイルが実際に作られる」という点です。
戻り値は、その一時ファイルの「絶対パス」です。拡張子は .tmp になります。

つまり、「一時ファイルのパスをもらう」だけでなく、「ファイル自体ももう存在している」状態になります。
あとはこのパスに対して File.WriteAllTextFileStream などで自由に読み書きできます。


一時ファイルのライフサイクル 「作る→使う→必ず消す」

典型的な流れをコードで見る

一時ファイルは「作りっぱなし」にしてはいけません。
作業が終わったら、必ず削除する、というのが鉄則です。

典型的な流れを一つのサンプルで見てみましょう。

using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        string tempFilePath = Path.GetTempFileName();
        Console.WriteLine("一時ファイル: " + tempFilePath);

        try
        {
            string content = "これは一時ファイルに書き込むテキストです。";

            File.WriteAllText(tempFilePath, content, Encoding.UTF8);

            string read = File.ReadAllText(tempFilePath, Encoding.UTF8);
            Console.WriteLine("読み出した内容: " + read);

            Console.WriteLine("ここで本来の処理(アップロード、変換など)を行うイメージです。");
        }
        finally
        {
            if (File.Exists(tempFilePath))
            {
                File.Delete(tempFilePath);
                Console.WriteLine("一時ファイルを削除しました。");
            }
        }
    }
}
C#

ここで深掘りしたいポイントは二つです。

一つ目は、「try-finally で囲んでいる」ことです。
途中で例外が発生しても、finally ブロックは必ず実行されるので、一時ファイルを確実に削除できます。

二つ目は、「削除前に File.Exists で存在チェックをしている」ことです。
処理の途中で別の箇所が削除している可能性もあるので、「存在していたら消す」という書き方にしておくと安全です。

using と FileStream を組み合わせるパターン

ストリームで扱いたい場合は、FileStreamusing を組み合わせることが多いです。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string tempFilePath = Path.GetTempFileName();
        Console.WriteLine("一時ファイル: " + tempFilePath);

        try
        {
            using (var stream = new FileStream(
                tempFilePath,
                FileMode.Open,
                FileAccess.ReadWrite,
                FileShare.None))
            {
                byte[] data = { 1, 2, 3, 4, 5 };
                stream.Write(data, 0, data.Length);

                stream.Position = 0;

                int b;
                Console.Write("読み出し: ");
                while ((b = stream.ReadByte()) != -1)
                {
                    Console.Write(b + " ");
                }
                Console.WriteLine();
            }
        }
        finally
        {
            if (File.Exists(tempFilePath))
            {
                File.Delete(tempFilePath);
                Console.WriteLine("一時ファイルを削除しました。");
            }
        }
    }
}
C#

using によってストリームは確実に閉じられますが、ファイル自体は残るので、やはり最後に File.Delete が必要です。
「リソースの解放(ストリームを閉じる)」と「ファイルの削除」は別物だ、という感覚を持っておくと混乱しません。


実務で使える一時ファイルユーティリティクラス

一時ファイルを「使い捨てオブジェクト」として扱う

毎回 try-finally と Delete を書くのは面倒なので、「使い終わったら自動で消える一時ファイル」をクラスとして用意しておくと便利です。
IDisposable を実装して、using で囲んだら最後に削除される、というイメージです。

using System;
using System.IO;

public sealed class TempFile : IDisposable
{
    public string Path { get; }

    public TempFile()
    {
        Path = System.IO.Path.GetTempFileName();
    }

    public void Dispose()
    {
        try
        {
            if (File.Exists(Path))
            {
                File.Delete(Path);
            }
        }
        catch
        {
        }
    }
}
C#

使い方はとてもシンプルです。

class Program
{
    static void Main()
    {
        using (var temp = new TempFile())
        {
            Console.WriteLine("一時ファイル: " + temp.Path);

            File.WriteAllText(temp.Path, "一時データ");

            string read = File.ReadAllText(temp.Path);
            Console.WriteLine("読み出し: " + read);
        }

        Console.WriteLine("using を抜けた時点で一時ファイルは削除済みです。");
    }
}
C#

ここでの重要ポイントは、「一時ファイルのライフサイクルをクラスに閉じ込めている」ことです。
呼び出し側は「using で囲む」というルールだけ守れば、削除漏れを心配しなくてよくなります。


Path.GetTempFileName と Path.GetRandomFileName の違い

GetTempFileName は「ファイルを作る」、GetRandomFileName は「名前だけ」

一時ファイル関連でよく出てくるもう一つのメソッドが Path.GetRandomFileName() です。
これは「ランダムなファイル名(文字列)を返すだけ」で、ファイル自体は作りません。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string randomName = Path.GetRandomFileName();
        Console.WriteLine("ランダム名: " + randomName);

        string tempDir = Path.GetTempPath();
        string tempFilePath = Path.Combine(tempDir, randomName);

        Console.WriteLine("一時ファイル候補: " + tempFilePath);
    }
}
C#

GetTempFileName は「一時フォルダに 0 バイトのファイルを実際に作る」のに対して、
GetRandomFileName は「衝突しにくいランダムな名前だけを返す」という違いがあります。

実務では、次のような使い分けが多いです。

すぐに使う一時ファイルが欲しい → Path.GetTempFileName
自分でフォルダを決めて、その中にランダム名でファイルを作りたい → Path.GetRandomFileNameFile.Create などを組み合わせる

ランダム名+自前作成のユーティリティ例

自分で一時フォルダを決めて、その中にランダム名で一時ファイルを作るユーティリティもよく使います。

public static class TempFileUtil
{
    public static string CreateTempFileIn(string directory)
    {
        if (string.IsNullOrWhiteSpace(directory))
        {
            throw new ArgumentException("ディレクトリが空です。", nameof(directory));
        }

        Directory.CreateDirectory(directory);

        string fileName = Path.GetRandomFileName();
        string fullPath = Path.Combine(directory, fileName);

        using (File.Create(fullPath))
        {
        }

        return fullPath;
    }
}
C#

これを使えば、例えば「アプリ専用の一時フォルダ」を作って、その中だけで一時ファイルを管理する、といった設計ができます。


一時ファイルを業務で使うときの注意点

削除しないと「Temp がゴミだらけ」になる

一時ファイルは「使い捨て」が前提なので、削除しないとどんどん溜まっていきます。
長期間動き続けるバッチやサービスでは、これがディスク圧迫の原因になります。

だからこそ、「一時ファイルを作ったら、必ずどこかで消す」というルールを徹底する必要があります。
TempFile クラスのように、「削除を忘れにくい形」にしておくのは、そのための工夫です。

セキュリティと機密情報

一時ファイルには、機密性の高いデータ(個人情報、トークン、パスワードなど)が一時的に書かれることもあります。
削除したからといって、ディスク上のデータが完全に消えるわけではない、という点も頭の片隅に置いておくとよいです。

本当に機密性が高い場合は、「そもそもディスクに書かない」「暗号化して書く」「OS の暗号化機能が有効な領域を使う」など、別の対策も検討します。
ただ、一般的な業務アプリでは、「不要になったらすぐ削除する」だけでもリスクはかなり下がります。


まとめ 実務で使える「一時ファイル作成」ユーティリティの考え方

一時ファイルは、「本番データを汚さずに、安全に作業するための一時的な作業机」です。
C# では Path.GetTempPathPath.GetTempFileName を使うことで、OS 標準の一時フォルダに簡単に一時ファイルを作れます。

大事なのは、「作ること」よりも「どう片付けるか」です。
try-finally で必ず削除する、IDisposableTempFile クラスでライフサイクルを閉じ込める、といった工夫をしておくと、削除漏れによるトラブルを防げます。

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