从SQL Server文本列解压缩到图像列

| 我将各种格式(.png,.jpg,.bmp等)的图像作为压缩文本存储在SQL Server 2005表的文本列中。我需要阅读该行,解压缩图像并将其存储在另一个表的图像列中。 我正在使用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的过程中对其进行了压缩。似乎在插入之前已将格式信息添加到数据的开头。 看看这些数据,对这个图像数据如何被操纵的人会有任何见解吗?同样,我需要将未压缩的图像数据放入一列数据类型中,该数据类型有利于阅读以显示在网页上。 编辑:好的,我很困惑。执行以下代码将产生错误“无法将参数值从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-ZIPV3数据,因为我还没有弄清楚如何解码FORMAT-ZIP2字符串。以下是V2数据的采样。如果有人能够确定编码,请告诉我。如果使用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...
    
已邀请:
好的,使用您提供的包含数据格式的更新,您可以得出一些结论。 数据是实际的字符串。怀疑它是Base64编码的字符串,我做了一个小测试,并在包含zip文件的字节流中使用了“ 4”。看起来像这样:
UEsDBBQAAAAIAJJyYyk3M56F+QIAA...
啊哈!您有一个真实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(...);
    ...
}
如果数据“真的很长”,您将需要将其从该表中流式传输,而不是仅仅将其读取为大字符串并进行转换。我不知道可以有多大的文本列,但是假设它可以是500mb,您不想要500mb的字符串,并且您不想使用Convert.FromBase64String进行500mb的字符串的转换。 ()。在这种情况下,您需要在System.Security.Cryptography命名空间中使用Base64Stream或FromBase64Transform类。 编辑评论。压缩图像数据是一种倒退。图像可能已经被压缩。但是要通过执行base64编码来增加这种落后性,从而扩展数据... ???那是三倍倒退。那根本就没有意义。我了解这是您的供应商提供它的方式。 好的,随着您的更新,请使用以下格式:
ImageID ImageData
1          FORMAT-ZIPV2 504B03041400020008005157422A2E25FDBAF26701008D6901000E...
2          FORMAT-ZIPV2 504B03041400020008009159422A7FC94BA2B2540500D35705000E...
该数据仍然是zipfile数据,但是被编码为简单的十六进制数字。您需要将其转换为字节数组。这是一些执行此操作的代码。
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);
                }
            }
        }
    
为了回答类似的问题,sqlmonster.com上的某人提供了一个漂亮的VarBinaryStream类。列类型为
varbinary(max)
。 如果您的数据以varbinary(max)存储,并且为zip格式,则可以使用该类实例化VarBinaryStream,然后在该实例周围实例化ZipInputStream,然后使用ba-da-boom。只需从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))
        {
           ....
        }
    }
}
如果图像很小,那么您可能不希望所有这些流媒体内容。如果该列是n小于8000的
binary(n)
varbinary(n)
,则只需使用
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 
最后,我将质疑将zip压缩应用于.jpg图像及类似图像的智慧。 jpg格式已被压缩;在将数据放入SQL Server之前再次对其进行压缩不会导致数据明显变小。这只会增加处理时间。如果可能的话,建议您重新考虑存储压缩图像的设计。     
SharpZip Wiki上的示例使用Stream对象-尽管该示例确实使用了File,但是您可以在此处轻松地使用MemoryStream对象,并且该示例也可以工作。     

要回复问题请先登录注册