从MySQL数据库读取BLOB图像

6

我在读取MySQL数据库中的blob时遇到了一些问题。我已经成功地将它插入到数据库中,但似乎无法读回。我知道有些人可能会想“为什么他要使用数据库来存储图像的blob,而不是文件路径/文件名”,但我希望具备灵活性,因为很多这些图像将被存储在服务器上而不是本地,这可以优化效率,并允许我在需要时将图像移动到本地。我按照(简短的)教程编写了以下方法来接收blob:

public void getBlob(string query, string fileOut)
    {
        if (this.OpenConnection() == true)
        {
            MySqlCommand cmd = new MySqlCommand(query, mConnection);

            //the index number to write bytes to
            long CurrentIndex = 0;

            //the number of bytes to store in the array
            int BufferSize = 100;

            //The Number of bytes returned from GetBytes() method
            long BytesReturned;

            //A byte array to hold the buffer
            byte[] Blob = new byte[BufferSize];


            //We set the CommandBehavior to SequentialAccess
            //so we can use the SqlDataReader.GerBytes() method.

            MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

            while (reader.Read())
            {
                FileStream fs = new FileStream(DeviceManager.picPath + "\\" + reader["siteBlobFileName"].ToString(), FileMode.OpenOrCreate, FileAccess.Write);
                BinaryWriter writer = new BinaryWriter(fs);
                CurrentIndex = 0;
                BytesReturned = reader.GetBytes(1, CurrentIndex, Blob, 0,BufferSize);  

                while (BytesReturned == BufferSize)
                {
                    writer.Write(Blob);
                    writer.Flush();
                    CurrentIndex += BufferSize;
                    BytesReturned = reader.GetBytes(1, CurrentIndex, Blob, 0, BufferSize);
                }

                writer.Write(Blob, 0, (int)BytesReturned);
                writer.Flush();
                writer.Close();
                fs.Close();
            }
            reader.Close();

            this.CloseConnection();
        }
    }

我正在这样调用它。

 mDBConnector.getBlob("SELECT siteMapPicture, siteBlobFilename FROM sites WHERE siteID = '" + DeviceManager.lastSite + "'", DeviceManager.picPath + "mappicsite" + DeviceManager.lastSite);


PBSite.BackgroundImage = Image.FromFile(DeviceManager.picPath + "mappicsite" + DeviceManager.lastSite);

然而,当BytesReturned = reader.GetBytes(1, CurrentIndex, Blob, 0,BufferSize)时出错,并显示"只能在二进制或GUID列上调用GetBytes"。我猜这与我的数据库字段类型有关,但将列更改为二进制类型意味着我必须将其存储为一种blob类型,但我想将文件名保留为常规字符串。我是否遗漏了什么?或者还有其他方法可以实现这一点?
编辑1:我认为bytesreturned的第一个参数与reader中的列有关。将其设置为0会出现错误"尝试使用SequentialAccess读取先前的列无效",我将进一步研究。
编辑2:移除sequential access后,我得到了大小为13字节的文件(这可能是第一行),所以我可能正在错误地读取列的顺序...
编辑3:我认为产生此错误的原因是我的输入方式不正确。更改了此方法后,我的saveBlob现在如下所示:
public void saveBlob(string filePath, string fileName, string siteID)
    {
        if (this.OpenConnection() == true)
        {

            //A stream of bytes that represnts the binary file
            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);

            //The reader reads the binary data from the file stream
            BinaryReader reader = new BinaryReader(fs);

            //Bytes from the binary reader stored in BlobValue array
            byte[] BlobValue = reader.ReadBytes((int)fs.Length);

            fs.Close();
            reader.Close();


            MySqlCommand cmd = new MySqlCommand();
            cmd.Connection = mConnection;
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = "INSERT INTO x (y, z) VALUES (@BlobFile, @BlobFileName)";

            MySqlParameter BlobFileNameParam = new MySqlParameter("@BlobFileName", SqlDbType.NChar);
            MySqlParameter BlobFileParam = new MySqlParameter("@BlobFile", SqlDbType.Binary);
            cmd.Parameters.Add(BlobFileNameParam);
            cmd.Parameters.Add(BlobFileParam);
            BlobFileNameParam.Value = fileName;
            BlobFileParam.Value = BlobValue;



                cmd.ExecuteNonQuery();

            this.CloseConnection();
        }
    }

我已经通过调试器运行了程序,blobvalue和blobfileparam(@blobfile)的大小都是完整的(约150k),但在执行查询时出现错误,显示以下错误信息:

"unable to cast object of type 'system.byte[]' to type 'system.iconvertible"

我已经查看了代码,并尝试将类型从二进制更改为图像以允许更大的文件,但出现相同的错误。有人知道这个新信息的详情吗?
编辑4:一切都已经修复。我注意到在我的代码中使用了:
 ("@BlobFile", SqlDbType.Binary);

将这些类型更改为"MySqlDbType"(笨蛋),这样就可以选择Blob类型了。现在事情终于按预期工作了 :)


1
我不是 C# 专家,但你正在选择两列 - siteMapPicturesiteBlobFilename - 它们都是 BLOB 还是其中一个是 varchar/char/text? - N.B.
siteMapPicture是一个BLOB,siteBlobFilename是一个varchar。 - Kestami
不是C#开发人员,但您的blob字段不应该是列#0吗?而您正在尝试在列#1上获取字节,这将是路径字段? - Marc B
我刚刚在测试时移动了这个文件,大约30分钟前,现在不再出错了,但是只给了一个大小为13字节的文件...我可能会检查一下我的存储blob是否完好。 - Kestami
1个回答

3

您尝试过先简化吗?不要每次读取BLOB 100个字节,而是将代码简化为只读取所有字节到文件中。这样您可以轻松排除数据层问题。

下面的文档还建议您将文件大小作为另一列存储:使用Connector/NET处理BLOB数据


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接