从数据库中读取 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

原文由 bjjrolls 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

你让它变得比它需要的更困难。之所以使用 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,甚至不需要创建 temp Image 除非您不需要显示它。

总而言之,天花板猫让它恢复得很好(图像是 1.4 MB,放大;另一个 15.4 MB 图像的测试也有效 - 两者都比我愿意存储在数据库中的要大)。:

在此处输入图像描述

根据使用方式,考虑将图像存档到文件系统上的某个位置并仅保存文件名 - 可能添加 Id 以确保名称是唯一的,并有助于在视觉上将它们链接到记录。大量数据不仅会使数据库膨胀,而且在与字节之间进行转换时显然会产生一些开销,这是可以避免的。


如果您想/需要在关联的应用程序完成后的某个时间点删除它们(不是问题的真正组成部分),然后使用特定目录中的临时文件,这样您就可以删除其中的所有内容(条件为1 )应用程序结束或启动时:

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

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

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

原文由 Ňɏssa Pøngjǣrdenlarp 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

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

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

原文由 Dan Guzman 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进