3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プリザンターに登録した添付ファイルのデータを全て取得したい

Posted at

はじめに

なんとなく「プリザンターのデータベース内にある添付ファイルを取りたい」という好奇心で調べた結果、プログラムで出力した、という内容となります。

プリザンターに登録した添付ファイルを取得するには

プリザンターで作成したテーブルを別環境へコピーする時サイトパッケージ機能のエクスポートを利用します。
このエクスポート機能は制限事項として添付ファイルおよび画像はエクスポートできません。
デフォルトの設定だとテーブルのバイナリに格納されてしまうので、バイナリデータから復元するツールをC#で作ってみました。

構成

  • OS:windows 11 Pro
  • DB:SQL Server 2019
  • プリザンター:バージョン 1.4.6.4
  • C#:.NET 8
  • Visual Studio 2022

プリザンターの添付ファイルの場所

デフォルトの設定では添付ファイルはBinariesテーブルに格納されています。
また、添付ファイルをローカルフォルダに変更する事も可能です。

SQL文にして必要そうな所をコメント

こんな感じだと思います。

SELECT
 Bin         -- バイナリデータが格納されている列
,FileName    -- ファイル名(プリザンター上からカメラ等を起動して撮った写真には拡張子が無い?)
,Extension   -- 拡張子(カメラ等で起動して撮ったものには拡張子がないと思われる)
,Size        -- ファイルサイズ
,ContentType -- よくあるContentType
FROM Binaries
WHERE Title IS NOT NULL -- タイトルがnullのものは初期値

プログラム仕様

プログラム直下にBinariesフォルダを作成し、テーブルの中にあるバイナリデータをファイルに変換して格納していきます。

プログラムの作成

Visual Studio 2022を起動し新しいプロジェクトの作成を選択します。

image.png

コンソールアプリ(C#)を選択します。

image.png

プロジェクト名を指定します。

image.png

.NET8.0を指定しプロジェクトを作成します。

image.png

ソリューションエクスプローラーからProgram.csを選択し、編集します。

image.png

実際のプログラム

コンソールアプリケーションを想定しているので「実行すれば動く」という感じになっています。
無駄な処理を書かないようにしようと試みましたが、結構な長さになってしまいました。

Program.cs
using Microsoft.Data.SqlClient;

class Program
{
    static void Main(string[] args)
    {
        // 接続文字列
        string connectionString = "ここに接続文字列を入力してください";

        // 添付ファイルを出力するディレクトリ(プログラム実行直下)
        string outputDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Binaries");

        try
        {
            // フォルダが存在しない場合は作成
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            // SQL Serverからデータを取得
            string query = @"SELECT Bin, FileName, Extension, Size, ContentType FROM Binaries WHERE Title IS NOT NULL";

            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand(query, connection))
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        // バイナリデータ、ファイル名、拡張子を取得
                        byte[] fileData = (byte[])reader["Bin"];
                        string fileName = reader["FileName"].ToString();
                        string extension = reader["Extension"].ToString();
                        string contentType = reader["ContentType"].ToString();

                        // 拡張子がない場合は拡張子を付ける
                        if (string.IsNullOrWhiteSpace(extension))
                        {
                            if (contentType == "image/jpeg")
                            {
                                fileName += ".jpeg";
                            }
                        }

                        // 同一の名称がある場合は連番を付ける
                        fileName = HandleDuplicateFileName(outputDirectory, fileName);

                        // フルパスを組み立てる
                        string filePath = Path.Combine(outputDirectory, fileName);

                        // ファイルを書き込む
                        File.WriteAllBytes(filePath, fileData);
                        Console.WriteLine($"ファイルを保存しました: {filePath}");
                    }
                }
            }
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine($"ファイルアクセス権限エラー: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"エラーが発生しました: {ex.Message}");
        }

        Console.WriteLine("終了。");
    }

    // 重複するファイル名に連番を付ける
    private static string HandleDuplicateFileName(string directory, string fileName)
    {
        // 拡張子とファイル名を分割
        string extension = Path.GetExtension(fileName);
        string originalFileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);

        int count = 1;

        // ファイル名が重複している場合、拡張子の前に数字を付加する
        while (File.Exists(Path.Combine(directory, fileName)))
        {
            fileName = $"{originalFileNameWithoutExtension}_{count}{extension}";
            count++;
        }

        return fileName;
    }

}

作成中に感じた感想

期待通りのプログラム動作になりましたが、全データを網羅していないので不足感がありました。様々なデータを入力して検証していければと思います。

次はテーブル毎に出力する等の制御可能なツールができないか検討してきたいと思います。

また、プリザンターがSQL ServerだけではなくPostgreSQLも対応しているので単純なSQLで作ってみましたが、環境がないため動作するか検証できていません(ツールを作るうえで複数の環境が必要だなと感じました)

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?