从数据库中读取SQL Varbinary Blob

我正在努力将文件保存到sql blob到varbinary(max)列,并且现在有了保存方面的工作(我相信)。

我无法弄清楚如何读取数据,因为我正在使用存储过程检索我的数据库值我应该能够访问列数据,如ds.Tables [0] .Rows [0] [ “blobData”]; 所以我有必要像我在下面的例子中看到的那样有一个SQLCommand等:

private void OpenFile(string selectedValue) { String connStr = "...connStr"; fileName = ddlFiles.GetItemText(ddlFiles.SelectedItem); using (SqlConnection conn = new SqlConnection(connStr)) { conn.Open(); using (SqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT BLOBData FROM BLOBTest WHERE testid = " + selectedValue; using (SqlDataReader dr = cmd.ExecuteReader()) { while (dr.Read()) { int size = 1024 * 1024; byte[] buffer = new byte[size]; int readBytes = 0; int index = 0; using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) { while ((readBytes = (int)dr.GetBytes(0, index, buffer, 0, size)) > 0) { fs.Write(buffer, 0, readBytes); index += readBytes; } } } } } } 

当我可以在没有sqlcommand的情况下访问我需要的列时,是否有更简单的方法可以执行此操作?

希望我在我的问题中足够清楚,如果不是那么问我会详细说明!

更新:

现在情况如此 – 我有我的存储过程返回的blobData列的值,并且可以将其传递到内存流并调用’LoadDocument(memStream); 但是这会导致乱码文本而不是我实际显示的文件。

我现在的问题是有没有办法获得完整的路径,包括存储在SQL Blob中的文件的文件扩展名? 我目前正在考虑使用Filetable,希望我能够获得完整的路径。

更新2:

我尝试创建一个临时文件并阅读这个无济于事(仍然是胡言乱语)

  string fileName = System.IO.Path.GetTempFileName().ToString().Replace(".tmp", fileExt); using (MemoryStream myMemoryStream = new MemoryStream(blobData, 0, (int)blobData.Length, false, true)) { using (FileStream myFileStream1 = File.Create(fileName)) { myMemoryStream.WriteTo(myFileStream1); myMemoryStream.Flush(); myMemoryStream.Close(); myFileStream1.Flush(); myFileStream1.Close(); FileInfo fi = new FileInfo(fileName); Process prc = new Process(); prc.StartInfo.FileName = fi.FullName; prc.Start(); } } 

干杯,H

你使它变得比它需要的更困难。 这是使用MySQL只是因为它很方便 – 提供者都工作几乎相同。 需要调整一些东西来处理非常大的数据项(比DB Provider更多的服务器)。

保存图像

 string sql = "INSERT INTO BlobDemo (filename, fileType, fileData) VALUES (@name, @type, @data)"; byte[] imgBytes; using (MySqlConnection dbCon = new MySqlConnection(MySQLConnStr)) using (MySqlCommand cmd = new MySqlCommand(sql, dbCon)) { string ext = Path.GetExtension(filename); dbCon.Open(); cmd.Parameters.Add("@name", MySqlDbType.String).Value = "ziggy"; cmd.Parameters.Add("@data", MySqlDbType.Blob).Value = File.ReadAllBytes(filename); cmd.Parameters.Add("@tyoe", MySqlDbType.String).Value = ext; int rows = cmd.ExecuteNonQuery(); } 

文件数据直接提供给DB Provider

有没有办法获得完整的路径,包括存储在SQL Blob中的文件的文件扩展名?

不。您的代码和上面的代码是保存构成图像或任何文件的字节

阅读Img数据

这将读回数据,将其保存到文件并启动相关的应用程序:

 string SQL = "SELECT itemName, itemData, itemtype FROM BlobDemo WHERE Id = @id"; string ext = ""; string tempFile = Path.Combine(@"C:\Temp\Blobs\", Path.GetFileNameWithoutExtension(Path.GetTempFileName())); using (MySqlConnection dbCon = new MySqlConnection(MySQLConnStr)) using (MySqlCommand cmd = new MySqlCommand(SQL, dbCon)) { cmd.Parameters.Add("@id", MySqlDbType.Int32).Value = 14; dbCon.Open(); using (MySqlDataReader rdr = cmd.ExecuteReader()) { if (rdr.Read()) { ext = rdr.GetString(2); File.WriteAllBytes(tempFile + ext, (byte[])rdr["itemData"]); } } // OS run test Process prc = new Process(); prc.StartInfo.FileName = tempFile + ext; prc.Start(); } 
  • 1 读回的字节数匹配
  • 1 关联的应用程序与图像一起发布得很好
  • 1 图片显示在图片框中

在这两种情况下,无论文件类型如何, File.ReadAllBytes()File.WriteAllBytes()都将为您完成大部分工作。

无需一次挖出1k数据。 如果blob类似于您希望在应用程序中使用的图像:

 using (MySqlDataReader rdr = cmd.ExecuteReader()) { if (rdr.Read()) { ext = rdr.GetString(2); using (MemoryStream ms = new MemoryStream((byte[])rdr["imgData"])) { picBox.Image = Image.FromStream(ms); } } } 

blob字节可以被馈送到memstream,甚至不需要创建临时Image除非你不需要显示它。

总而言之,Ceiling Cat让它恢复得很好(图像是1.4 MB,缩放;另一个15.4 MB图像的测试也工作 – 两者都比我想要存储在DB中的大):

在此处输入图像描述

根据使用方式的不同,请考虑将图像存档到文件系统的某个位置,只需保存文件名 – 也许添加了Id以确保名称是唯一的,并帮助将它们直观地链接到记录。 大型数据不仅会使数据库膨胀,而且显然有一些开销涉及到可以避免的字节转换。


如果你想/需要在关联的应用程序完成之后的某个时刻删除它们(实际上不是问题的一个组成部分),那么在特定目录中使用临时文件,这样你就可以删除其中的所有内容(有条件地为1 )应用程序结束或启动时:

 private string baseAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Company Name", "Product Name", "Temp Files"); 

附加临时文件名和单个文件的实际扩展名。 或者,您可以维护List trashCan以存储您创建的每个文件的名称以便稍后删除。

1每当您删除它们时, 允许该文件仍然可以在与该扩展程序关联的应用程序中打开。

当数据存储在varbinary(MAX)列中时,您将需要使用SqlCommand来检索数据,除非您使用FileTable ,它允许通过UNC路径访问内容,类似于存储在文件系统上的常规文件,但由SQL管理服务器。

如果blob的大小可能很大,那么您当前使用的“块”技术将减少内存需求,但代价是更冗长的代码。 对于合理大小的blob大小,您可以在不使用分块方法的情况下立即读取整个列内容。 这是否可行取决于blob的大小和客户端可用内存。

 var buffer = (byte[])cmd.ExecuteScalar(); fs.Write(buffer, 0, buffer.Length); 

使用.NET SQL Server提供程序,您可以使用一个鲜为人知但很酷的类SqlBytes 。 它专门用于映射varbinary字段,但没有很多关于如何使用它的示例。

以下是如何使用它保存到数据库(您可以使用存储过程或直接SQL,就像我在此演示的那样,我们只假设MyBlobColumn是varbinary )。

 string inputPath = "YourInputFile"; using (var conn = new SqlConnection(YourConnectionString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { // note we define a '@blob' parameter in the SQL text cmd.CommandText = "INSERT INTO MyTable (Id, MyBlobColumn) VALUES (1, @blob)"; using (var inputStream = File.OpenRead(inputPath)) { // open the file and map it to an SqlBytes instance // that we use as the parameter value. var bytes = new SqlBytes(inputStream); cmd.Parameters.AddWithValue("blob", bytes); // undercovers, the reader will suck the inputStream out through the SqlBytes parameter cmd.ExecuteNonQuery(); } } } 

要将文件从数据库读入流中,您可以按照以下步骤操作。

 string outputPath = "YourOutputFile"; using (var conn = new SqlConnection(YourConnectionString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { // this is a regular direct SQL command, but you can use a stored procedure as well cmd.CommandText = "SELECT MyBlobColumn FROM MyTable WHERE Id = 1"; // note the usage of SequentialAccess to lower memory consumption (read the docs for more) using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { if (reader.Read()) { // again, we map the result to an SqlBytes instance var bytes = reader.GetSqlBytes(0); // column ordinal, here 1st column -> 0 // I use a file stream, but that could be any stream (asp.net, memory, etc.) using (var file = File.OpenWrite(outputPath)) { bytes.Stream.CopyTo(file); } } } } } 

使用这些技术,我们从未分配过任何byte []和MemoryStream实例,只是在SQL或文件流中使用。