1

さまざまな形式(.png、.jpg、.bmpなど)の画像が、SQLServer2005テーブルのテキスト列に圧縮テキストとして保存されています。行を読み取り、画像を解凍して、別のテーブルの画像列に保存する必要があります。

私はSharpZipライブラリを使用していますが、すべての例でファイルのソースと宛先を扱っています。変数から別の変数への解凍をカバーするものが見つかりません。これを説明するコードスニペットまたは関連するリソースへのリンクをいただければ幸いです。

編集:もう少し情報-データはTEXT列に保存されます。次のように表示されます(表示のためにテキスト列が省略されています)。

ImageID  ImageData
1       FORMAT-ZIPV3 UEsDBBQAAAAIAOV6wzxdTnDvshs...
2       FORMAT-ZIPV3 UEsDBBQAAAAIAAF2yjxGncjOLgA...
3       FORMAT-ZIPV3 UEsDBBQAAAAIAKd6yjyjnQNr6gg...
4       FORMAT-ZIPV3 UEsDBBQAAAAIALdNyzyrPC8EMJw...
5       FORMAT-ZIPV3 UEsDBBQAAAAIAA1rOD1nZY1t0f0...
6       FORMAT-ZIPV3 UEsDBBQAAAAIANZplj2seyJ+VmM...
7       FORMAT-ZIPV3 UEsDBBQAAAAIAC5vhD27LPbPcv8...
8       FORMAT-ZIPV3 UEsDBBQAAAAIAK1qKz5DJNH3xMg...
9       FORMAT-ZIPV3 UEsDBBQAAAAIAHVkEztC3th/9hs...
10     FORMAT-ZIPV3 UEsDBBQAAAAIAEtXKz7DXHUdvow...

私が確かに知っているのは、画像がテーブルに挿入される前に、SharpZipを使用してプロセスのある時点で圧縮されたことです。挿入前にデータの先頭にフォーマット情報が追加されたようです。

このデータを見て、この画像データがどのように操作されたかについて誰かが洞察を持っていますか?繰り返しになりますが、非圧縮の画像データを、Webページに表示するために読み取るのに役立つデータ型の列に入れる必要があります。

編集:わかりました、私は困惑しています。次のコードを実行すると、「パラメータ値をInt32からByte[]に変換できませんでした」というエラーが発生します。バイト配列の長さをバイト配列の値に入れているようです...

        commandUncompressed.Connection = connectionUncompressed;
        commandUncompressed.Parameters.Add("@Image_k", SqlDbType.VarChar, 10);
        commandUncompressed.Parameters.Add("@ImageContents", SqlDbType.Image);
        commandUncompressed.CommandText = sqlSaveImage;

        connectionUncompressed.Open();
        reader = command.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                Console.WriteLine(reader["Image_k"].ToString());  // Merely for testing
                String format = reader["ImageContents_Compressed"].ToString().Substring(0, 12);
                var offset = 13; //"FORMAT-ZIPV3 ".Length;
                var s = reader["ImageContents_Compressed"].ToString().Substring(offset);
                var bytes = Convert.FromBase64String(s);
                if (format == "FORMAT-ZIPV2 ")
                {
                    bytes = ConvertStringToBytes(s);    // Not a Base-64 encoded string? External conversion function utilized.
                }

                using (var zis = new ZipInputStream(new MemoryStream(bytes)))
                {
                    ZipEntry zipEntry = zis.GetNextEntry();   // Doesn't seem to work unless an entry has been referenced
                    byte[] buffer = new byte[zis.Length];
                    commandUncompressed.Parameters["@Image_k"].Value = reader["Image_k"].ToString();
                    commandUncompressed.Parameters["@ImageContents"].Value = zis.Read(buffer, 0, buffer.Length);
                    commandUncompressed.ExecuteNonQuery();

                }
            }
        }

ソーステキスト列からデータを正常に読み取っているようです。それを画像タイプパラメータに取り込む方法がわかりません。バッファ変数の値は、実際のバイトではなく、バイト配列の長さを示します。たぶんそれは、valueプロパティがバイト配列に対して通常表示するものですか?私はとても近くにいますが、まだ遠くにいます。:/

編集:わかりました、私はナックルヘッドです。私は次の修正を行いました、そしてそれはうまくいきます!

zis.Read(buffer, 0, buffer.Length)                            
commandUncompressed.Parameters["@ImageContents"].Value = buffer;

FORMAT-ZIP2文字列をデコードする方法がまだわからないため、現時点ではFORMAT-ZIPV3データしか処理できません。以下は、V2データのサンプルです。誰かがエンコーディングを決定できる場合は、私に知らせてください。ZIP形式の代わりにBZIPを使用してzip圧縮した場合は異なりますか?

ImageID ImageData
1          FORMAT-ZIPV2 504B03041400020008005157422A2E25FDBAF26701008D6901000E...
2          FORMAT-ZIPV2 504B03041400020008009159422A7FC94BA2B2540500D35705000E...
3          FORMAT-ZIPV2 504B0304140002000800685A422A0CAA51F4473A0600B97206000E...
4          FORMAT-ZIPV2 504B03041400020008001D5D422A770BD3ED201902002C4A02000E...
5          FORMAT-ZIPV2 504B0304140002000800325E422A4B6C2FB4045001001C6E01000E...
6          FORMAT-ZIPV2 504B03041400020008006F72422A5F793AC1A1F00200ECF302000E...
7          FORMAT-ZIPV2 504B0304140002000800D572422A1B348A731DE5000085EB00000E...
8          FORMAT-ZIPV2 504B03041400020008003D73422A8AEBB7F855640300DD1B04000E...
9          FORMAT-ZIPV2 504B03041400020008006368D528C5D0A6BA794900004A2502000E...
10         FORMAT-ZIPV2 504B03041400020008008E5B6C2A2D9E9C33D7AF05005CEC05000E...
4

3 に答える 3

3

同様の質問に答えて、sqlmonster.comの誰かが気の利いたVarBinaryStreamクラスを提供しました。の列タイプで機能しvarbinary(max)ます。

データがvarbinary(max)に格納されており、zip形式の場合は、そのクラスを使用してVarBinaryStreamをインスタンス化し、その周りにZipInputStreamをインスタンス化する、そこにいます。ZipInputStreamから読み取るだけです。

C#では次のようになります

using (var imageSrc = new VarBinarySource(connection, 
                                          "Table.Name", 
                                          "Column",
                                          "KeyColName",
                                          1))
{
    using (var s = new VarBinaryStream(imageSrc))
    {
        using(var zis = new ZipInputStream(s))
        {
           ....
        }
    }
}

画像が小さい場合は、このストリーミング関連のものをすべて必要としないでしょう。列がabinary(n)またはavarbinary(n)で、nが8000未満の場合は、SqlBinaryタイプを使用してすべてのデータをメモリに読み込み、その周りにMemoryStreamをインスタンス化します。よりシンプル。VB.NETでは、次のようになります。

Dim bytes as Bytes()
bytes = dr.GetSqlBinary(columnNumber)
Using ms As New MemoryStream(bytes)
    Using zis As New ZipInputStream(ms)
        ...
    End Using
End Using 

最後に、.jpg画像などにzip圧縮を適用することの知恵に疑問を投げかけます。jpg形式はすでに圧縮されています。データをSQLServerに配置する前に再度圧縮しても、データが大幅に小さくなることはありません。処理時間が長くなるだけです。可能であれば、圧縮された画像を保存するための設計を再検討することをお勧めします。

于 2011-04-16T09:44:58.197 に答える
1

さて、あなたが提供したデータ形式を含むアップデートで、あなたはいくつかの結論を引き出すことができます。

データは実際の文字列です。Base64でエンコードされた文字列であると疑って、小さなテストを行いConvert.ToBase64String()、zipファイルを含むバイトストリームで使用しました。次のようになります。 UEsDBBQAAAAIAJJyYyk3M56F+QIAA...

あはは!bonafide zipファイルのバイトデータのbase64エンコード(文字列)バージョンがあります。デコードするには、プレフィックスを取り除き、 FromBase64String()を使用してバイト配列を取得し、MemoryStreamに挿入してから、ZipInputStreamで読み取ります。

このようなもの:

var offset = "FORMAT-ZIPV3 ".Length(); 
var s = sqlReader["CompressedImage"].ToString().Substring(offset);
var bytes = Convert.FromBase64String(s);    
using (var zis = new ZipInputStream(new MemoryStream(bytes))) 
{
    ...
    zis.Read(...);
    ...
}

データが「非常に長い」場合は、データを大きな文字列に読み込んで変換するのではなく、そのテーブルからストリーミングする必要があります。テキスト列の大きさはわかりませんが、500 MBの場合、500 MBの文字列は必要なく、Convert.FromBase64String()を使用して500MBの文字列を変換する必要はありません。その場合、 Base64Stream、またはSystem.Security.Cryptography名前空間のFromBase64Transformクラスを使用する必要があります。


エディトリアルコメント。画像データをzip圧縮するのは一種の逆行です。画像はおそらくすでに圧縮されています。しかし、base64エンコードを実行してその後方性を複合し、それによってデータを拡張するには... ??? それはトリプルバックワードです。それはまったく意味がありません。それがあなたのベンダーがそれを供給した方法だと理解しています。


さて、あなたのさらなるアップデートで、これをフォーマットとして使用してください:

ImageID ImageData
1          FORMAT-ZIPV2 504B03041400020008005157422A2E25FDBAF26701008D6901000E...
2          FORMAT-ZIPV2 504B03041400020008009159422A7FC94BA2B2540500D35705000E...

そのデータは引き続きzipファイルデータですが、単純な16進数としてエンコードされます。それをバイト配列に変換する必要があります。これを行うためのコードをいくつか示します。

public static class ConvertEx
{
    static readonly String prefix= "FORMAT-ZIPV2 ";

    public static string ToHexString(byte[] b)
    {
        System.Text.StringBuilder sb1 = new System.Text.StringBuilder();
        int i = 0;
        for (i = 0; i < b.Length; i++)
        {
            sb1.Append(System.String.Format("{0:X2}", b[i]));
        }
        return sb1.ToString().ToLower();
    }

    public static byte[] ToByteArray(string s)
    {
        if (s.StartsWith(prefix))
        {
            System.Console.WriteLine("removing prefix");
            s = s.Substring(prefix.Length);
        }
        s= s.Trim(); // whitespace
        System.Console.WriteLine("length: {0}", s.Length);

        var r= new byte[s.Length/2];
        for (int i = 0; i < s.Length; i+=2)
        {
            r[i/2] = (byte) Convert.ToUInt32(s.Substring(i,2), 16);
        }
        return r;
    }
}

これは次のように使用できます。

        string s = GetStringContentFromDatabase()
        var decoded = ConvertEx.ToByteArray(s);

        using (var ms = new MemoryStream(decoded))
        {
            // use DotNetZip to read the zip file
            // SharpZipLib is something similar...
            using (var zip = ZipFile.Read(ms))
            {
                // print out the list of entries in the zipfile
                foreach (var e in zip)
                {
                    System.Console.WriteLine("{0}", e.FileName);
                }
            }
        }
于 2011-04-16T21:32:20.023 に答える
0

SharpZip Wikiの例ではStreamオブジェクトを使用しています。サンプルではFileを使用していますが、ここではMemoryStreamオブジェクトを簡単に使用でき、サンプルも同じように機能します。

于 2011-04-15T15:22:44.143 に答える