Sql server 如何在SQL Server数据库中以压缩二进制blob的形式存储和检索文件?

Sql server 如何在SQL Server数据库中以压缩二进制blob的形式存储和检索文件?,sql-server,vb.net,Sql Server,Vb.net,我在互联网上看到了很多示例代码,展示了如何压缩和解压缩文件系统上的文件,还有很多示例代码介绍了如何在SQL Server数据库中存储常规文件,但从来没有同时看到过。这是我到目前为止的代码。(我在VB.NET中使用实体框架,但这不是重点。我希望如此。) 这真的很接近。问题是,在提取时,文件会覆盖其自身的一部分,或者短时间停止。原始文件为18613KB,上存储和提取的文件为18446KB。我甚至不知道问题是否发生在存储或提取过程中 如您所见,我正在尝试.Flush和.Close()所有操作,以确保所

我在互联网上看到了很多示例代码,展示了如何压缩和解压缩文件系统上的文件,还有很多示例代码介绍了如何在SQL Server数据库中存储常规文件,但从来没有同时看到过。这是我到目前为止的代码。(我在VB.NET中使用实体框架,但这不是重点。我希望如此。)

这真的很接近。问题是,在提取时,文件会覆盖其自身的一部分,或者短时间停止。原始文件为18613KB,上存储和提取的文件为18446KB。我甚至不知道问题是否发生在存储或提取过程中


如您所见,我正在尝试
.Flush
.Close()
所有操作,以确保所有操作都正确完成。(是的,我可以尝试使用,但我不喜欢它最后会产生的所有缩进。)

关于使用块清理
对象的问题,Proputix是正确的,Max Vernon关于代码可读性的观点可能是正确的

这项工作:

Private Sub ButtonStore_Click(sender As Object, e As EventArgs) Handles ButtonStore.Click

    Dim contents As String

    Using ecfg_file = New FileStream("C:\Temp\X1_450_1750_60207003.ecfg", FileMode.Open)
        Using sr = New StreamReader(ecfg_file)
            contents = sr.ReadToEnd
        End Using
    End Using

    Using ms = New MemoryStream()
        Using comp_stream = New GZipStream(ms, CompressionMode.Compress)
            Using sw = New StreamWriter(comp_stream)
                sw.Write(contents)
            End Using
        End Using
        Using db As New Storage
            Dim bld = db.Builds.First
            bld.EcfgFile = ms.ToArray()
            db.SaveChanges()
        End Using
    End Using

    Debug.Print("Done")

End Sub


Private Sub ButtonExtract_Click(sender As Object, e As EventArgs) Handles ButtonExtract.Click

    Dim contents As String

    Using db As New Storage
        Dim bld = db.Builds.First
        Using ms = New MemoryStream()
            ms.Write(bld.EcfgFile.ToArray, 0, bld.EcfgFile.Length)
            ms.Position = 0
            Using decompression_stream = New GZipStream(ms, CompressionMode.Decompress, True)
                Using sr = New StreamReader(decompression_stream)
                    contents = sr.ReadToEnd
                End Using
            End Using
        End Using
    End Using

    Using ecfg_file = New FileStream("C:\Temp\asdf.ecfg", FileMode.Create)
        Using sw = New StreamWriter(ecfg_file)
            sw.Write(contents)
        End Using
    End Using

    Debug.Print("Done")

End Sub
简短答复:

您可能会发现CLR运行时函数,例如(中的示例实现)和有用的

长答覆:

我假设您将文件存储在数据库中的varbinary(max)列中,从我收集的信息来看,很遗憾,SQL Server没有按照您希望的方式使用页面压缩(或行压缩,或列存储索引,我假设扩展到了列存储_归档)来压缩大型对象(LOB)数据。作者本质上指出,这是因为跨多个页面的数据(LOB数据自然会这样)不会从这种压缩中受益


我正在寻找一个类似的解决方案,到目前为止,我倾向于使用CLR函数进行压缩,基本上是在将数据写入表之前压缩数据,然后在将其读回后反压缩。据我所知,这会带来一些后果,比如无法对压缩数据使用某些搜索功能,以及(根据)无法再对其进行异步读/写。

我会尝试在
Store\u单击
中创建一个新的临时文件,以验证读/压缩步骤是否正确。顺便说一句,
使用
不仅仅是一种风格上的东西-你有很多一次性物品没有被处理-使用
可以为你解决这些问题。CA会告诉你这一切。“我不喜欢它最后会产生的所有缩进”->缩进让你的代码在将来更容易阅读。我强烈建议您重新考虑,因为在代码中使用
块的好处远远超过您不缩进代码的偏好。另外,您的意图是什么?您是否试图压缩文件以节省SQL Server中的空间?如果是这样的话,您可以在表定义中使用
页面压缩
,并获得自动、透明的压缩。“CA会告诉您的。”什么是“CA”?是的,我只是想节省大约90%的空间需求,因为这些是可以很好压缩的XML文件<代码>页面压缩
对我来说是新的,但它(最终)必须在Azure中运行,我发现它在那里不受支持。我已经忘记了整个问题。尽管使用块导致代码正常工作,并且我得到了我想要的行为,但我放弃了在数据库中存储文件,开始使用Azure blob存储。让“文件系统”和数据库保持同步更痛苦,但blob存储空间比DB表空间便宜得多。你对压缩“边界”的评论很有趣,因为我无法有效地判断我的方法是否真的节省了磁盘空间。也许不是。
Private Sub ButtonStore_Click(sender As Object, e As EventArgs) Handles ButtonStore.Click

    Dim contents As String

    Using ecfg_file = New FileStream("C:\Temp\X1_450_1750_60207003.ecfg", FileMode.Open)
        Using sr = New StreamReader(ecfg_file)
            contents = sr.ReadToEnd
        End Using
    End Using

    Using ms = New MemoryStream()
        Using comp_stream = New GZipStream(ms, CompressionMode.Compress)
            Using sw = New StreamWriter(comp_stream)
                sw.Write(contents)
            End Using
        End Using
        Using db As New Storage
            Dim bld = db.Builds.First
            bld.EcfgFile = ms.ToArray()
            db.SaveChanges()
        End Using
    End Using

    Debug.Print("Done")

End Sub


Private Sub ButtonExtract_Click(sender As Object, e As EventArgs) Handles ButtonExtract.Click

    Dim contents As String

    Using db As New Storage
        Dim bld = db.Builds.First
        Using ms = New MemoryStream()
            ms.Write(bld.EcfgFile.ToArray, 0, bld.EcfgFile.Length)
            ms.Position = 0
            Using decompression_stream = New GZipStream(ms, CompressionMode.Decompress, True)
                Using sr = New StreamReader(decompression_stream)
                    contents = sr.ReadToEnd
                End Using
            End Using
        End Using
    End Using

    Using ecfg_file = New FileStream("C:\Temp\asdf.ecfg", FileMode.Create)
        Using sw = New StreamWriter(ecfg_file)
            sw.Write(contents)
        End Using
    End Using

    Debug.Print("Done")

End Sub