はじめに
なんとなく「プリザンターのデータベース内にある添付ファイルを取りたい」という好奇心で調べた結果、プログラムで出力した、という内容となります。
プリザンターに登録した添付ファイルを取得するには
プリザンターで作成したテーブルを別環境へコピーする時サイトパッケージ機能のエクスポートを利用します。
このエクスポート機能は制限事項として添付ファイルおよび画像はエクスポートできません。
デフォルトの設定だとテーブルのバイナリに格納されてしまうので、バイナリデータから復元するツールを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を起動し新しいプロジェクトの作成を選択します。
コンソールアプリ(C#)を選択します。
プロジェクト名を指定します。
.NET8.0を指定しプロジェクトを作成します。
ソリューションエクスプローラーから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で作ってみましたが、環境がないため動作するか検証できていません(ツールを作るうえで複数の環境が必要だなと感じました)