りおんクロニクル


SQLite × バイナリ保存|画像・PDF・ファイルを安全に扱う実務ガイド【2026年版】

Home【2026年版】C# / .NET入門と実践ガイド|基礎・業務アプリ開発・SQLite連携まで体系的に解説

SQLiteはBLOBカラムで任意のバイナリデータを保存できるため、 画像・PDF・その他ファイルをDBにまとめて管理したい、というニーズは多いです。 一方で、サイズ・パフォーマンス・バックアップ・セキュリティを考えずに突っ込むと、 「DBが巨大化して壊れやすくなる」リスクもあります。 この記事では、SQLiteにバイナリを保存する現実的な設計とC#実装パターンを整理します。

この記事でわかること
・SQLiteのBLOBカラム設計
・画像・PDF・任意ファイルの保存/取得コード(C#)
・DB内保存 vs 外部ファイル管理のメリット・デメリット
・ファイルサイズの目安とパフォーマンス
・バックアップ・セキュリティの考え方
・業務アプリ向けベストプラクティス

1. SQLiteでバイナリを扱う基本:BLOBカラム

SQLiteでは、バイナリデータはBLOB型で保存します。 画像専用型などはなく、すべて「バイト列」として扱います。

■ 典型的なテーブル設計例

CREATE TABLE Files (
    Id          INTEGER PRIMARY KEY AUTOINCREMENT,
    FileName    TEXT        NOT NULL,
    ContentType TEXT        NOT NULL, -- image/png, application/pdf など
    Data        BLOB        NOT NULL,
    CreatedAt   TEXT        NOT NULL
);

最低限、ファイル名・ContentType・バイナリ本体を持たせておくと扱いやすくなります。

2. C#での保存:ファイル → BLOB

C#(Microsoft.Data.Sqlite)からファイルを読み込み、 そのままBLOBとしてINSERTする基本パターンです。

■ ファイルをDBに保存するコード例

using Microsoft.Data.Sqlite;

public void SaveFileToDb(string filePath)
{
    var cs = "Data Source=files.db";

    var fileName = Path.GetFileName(filePath);
    var contentType = GetContentType(filePath); // 拡張子から判定するなど
    var bytes = File.ReadAllBytes(filePath);

    using var con = new SqliteConnection(cs);
    con.Open();

    var sql = @"
        INSERT INTO Files (FileName, ContentType, Data, CreatedAt)
        VALUES (@name, @type, @data, @createdAt);
    ";

    using var cmd = new SqliteCommand(sql, con);
    cmd.Parameters.AddWithValue("@name", fileName);
    cmd.Parameters.AddWithValue("@type", contentType);
    cmd.Parameters.AddWithValue("@data", bytes);
    cmd.Parameters.AddWithValue("@createdAt", DateTime.UtcNow.ToString("o"));

    cmd.ExecuteNonQuery();
}

private string GetContentType(string path)
{
    var ext = Path.GetExtension(path).ToLowerInvariant();
    return ext switch
    {
        ".png"  => "image/png",
        ".jpg"  => "image/jpeg",
        ".jpeg" => "image/jpeg",
        ".pdf"  => "application/pdf",
        _       => "application/octet-stream"
    };
}

小さめのファイルであれば File.ReadAllBytes で問題ありませんが、 大きなファイルはストリームで少しずつ読み書きする方が安全です。

3. C#での取得:BLOB → ファイル/画像

■ DBからファイルを取り出して保存する例

public void ExportFileFromDb(int id, string outputPath)
{
    var cs = "Data Source=files.db";

    using var con = new SqliteConnection(cs);
    con.Open();

    var sql = "SELECT FileName, ContentType, Data FROM Files WHERE Id = @id";
    using var cmd = new SqliteCommand(sql, con);
    cmd.Parameters.AddWithValue("@id", id);

    using var reader = cmd.ExecuteReader();
    if (!reader.Read()) return;

    var fileName = reader.GetString(0);
    var contentType = reader.GetString(1);
    var bytes = (byte[])reader["Data"];

    var path = Path.Combine(outputPath, fileName);
    File.WriteAllBytes(path, bytes);
}

WPFなどで画像として表示したい場合は、 byte[] から BitmapImage に変換してバインドします。

■ byte[] → BitmapImage(WPF)

public static BitmapImage ToBitmapImage(byte[] bytes)
{
    using var ms = new MemoryStream(bytes);
    var image = new BitmapImage();
    image.BeginInit();
    image.CacheOption = BitmapCacheOption.OnLoad;
    image.StreamSource = ms;
    image.EndInit();
    image.Freeze();
    return image;
}

4. DB内保存 vs 外部ファイル管理:どっちが正解?

バイナリを扱うとき、必ず出てくるのが 「DBに入れるか?ファイルとして置くか?」問題です。

■ DB内保存(BLOB)のメリット

■ DB内保存のデメリット

■ 外部ファイル管理のメリット

■ 外部ファイル管理のデメリット

現場感のある結論
・小規模/単体アプリ:DB内保存(BLOB)でもOK
・中〜大規模/長期運用:外部ファイル管理+DBはメタ情報のみ (または「サムネイルだけDB、原本はファイル」などのハイブリッド)

5. ファイルサイズとパフォーマンスの目安

SQLite自体は数GBクラスのDBも扱えますが、 1ファイルDBであることを忘れてはいけません。

■ 目安として意識したいライン

また、BLOBを多用するとVACUUMやバックアップ時間が伸びるため、 運用時のメンテナンス時間も考慮する必要があります。

6. トランザクションと一括保存

複数ファイルをまとめて保存する場合は、 トランザクションで一括処理するのが定番パターンです。

using var con = new SqliteConnection(cs);
con.Open();

using var tran = con.BeginTransaction();

try
{
    foreach (var filePath in filePaths)
    {
        var fileName = Path.GetFileName(filePath);
        var contentType = GetContentType(filePath);
        var bytes = File.ReadAllBytes(filePath);

        var sql = @"
            INSERT INTO Files (FileName, ContentType, Data, CreatedAt)
            VALUES (@name, @type, @data, @createdAt);
        ";

        using var cmd = new SqliteCommand(sql, con, tran);
        cmd.Parameters.AddWithValue("@name", fileName);
        cmd.Parameters.AddWithValue("@type", contentType);
        cmd.Parameters.AddWithValue("@data", bytes);
        cmd.Parameters.AddWithValue("@createdAt", DateTime.UtcNow.ToString("o"));
        cmd.ExecuteNonQuery();
    }

    tran.Commit();
}
catch
{
    tran.Rollback();
    throw;
}

これにより、途中でエラーが出ても中途半端な状態を防げると同時に、 パフォーマンスも大幅に向上します。

7. セキュリティとバックアップの観点

バイナリに個人情報・機密情報が含まれる場合、 セキュリティとバックアップの設計が重要になります。

■ セキュリティのポイント

■ バックアップのポイント

8. 業務アプリ向けベストプラクティス

まとめ:SQLiteのバイナリ保存は“規模と運用”で決める

「全部DBに入れれば楽」「全部ファイルにすれば軽い」の間に、 アプリの規模・運用・セキュリティに合わせた最適なポイントがあります。 この記事のパターンをベースに、 自分のプロジェクトにとってちょうどいいバイナリ保存戦略を設計してみてください。

前のページ  次のページ