Delphi 从长二进制数据中检索 JPG - JPEG 错误 #53

Delphi Retrieve JPG From Long binary data - JPEG error #53

我将许多 JPEG 图像作为 Long 二进制数据添加到 Access DB 中。现在我想使用 Delphi 代码将这些图像检索到 TImage 中。

对于这项工作,我写了下面的代码,但在 运行 之后它给了我一个 JPEG 错误 #53 错误。我在 Google 中搜索了这个错误代码,并尝试了一些解决方案,例如将图片另存为新的 JPG 格式,但这并没有改变任何东西。

此外,我发现了从数据库中检索图像的不同代码,但它们都给了我相同的 JPEG 错误 #53 错误。

问题出在哪里?

procedure RetrieveImage;
var
 Jpg : TGraphic;
 Stream: TStream;
 query : string;
 Field: TBlobField;
Begin
 Stream := nil;
 Jpg := nil;
 query := 'Select JPGFile From Table Where Name=' + QuotedStr(SoftName);
 Try
   With ADOQuery do
    Begin
      Try
         SQL.Clear;
         SQL.Add(query);
         Open;
         Field := TBlobField(FieldbyName('JPGFile'));
         Stream := CreateBlobStream(Field,bmRead);
         Jpg := TJpegImage.Create;
         Jpg.LoadFromStream(Stream);
         MainForm.PictureBox.Picture.Graphic:= Jpg;
      Finally
         Close;
      End;
    End;
Finally
  Stream.Free;
  Jpg.Free;
End;
End;

编辑:

我使用 C# 代码将 JPG 文件插入数据库(以下代码已简化):

    // Insert Data to Access tables
    private void InsertToTable(string connectionString, string query)
    {
        using (OleDbConnection connection = new OleDbConnection(connectionString))
        {
            try
            {
                connection.Close();
                using (OleDbCommand command = new OleDbCommand(query, connection))
                {
                    connection.Open();
                    using (OleDbDataReader reader = command.ExecuteReader())
                    {
                        reader.Close();
                    }
                    command.Cancel();
                }
                connection.Close();
            }
            finally
            {
                connection.Close();
            }
        }
    }

    // Insert Image into database
    private void SaveToDataBase(string jpegPath)
    {
        //jpegPath example is: (C:\Image.jpg)

        string FilePath = Application.StartupPath + directory + dbName;
        string MDBConnStr = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + FilePath + "; Jet OLEDB:Engine Type=5";

        // Convert Image to binary
        var image = File.ReadAllBytes(jpegPath);

        InsertToTable(MDBConnStr, $"INSERT INTO Table JPGFile VALUES('{image}')");                         
    }

在您的 C# 代码中,为什么要使用 ExecuteReader() 来执行 INSERT 语句?您应该改用 ExecuteNonQuery()

更重要的是,您实际上并没有将 image 字节数组的内容插入数据库,这就是 Delphi 的 TJPEGImage 稍后无法加载数据的原因.您的 SQL 查询被创建为 interpolated 字符串,但是您的 {image} 表达式不会像您认为的那样将原始字节插入到查询中。即使是这样,这也不是将原始字节插入“长二进制”字段的正确方法。

您需要改用参数化查询。在command.Parameters集合中添加一个OleDbParameter,将image数据传入数据库,在这里你将它的DbType属性设置为Binary,它的OleDbType 属性 到 BinaryLongVarBinaryVarBinary,它的 Value 属性 到你的 image字节数组。然后,您可以在 SQL 语句中引用该参数。

参见 Configuring parameters and parameter data types, especially the section on Using parameters with an OleDbCommand or OdbcCommand

试试像这样的东西:

// Insert Image into database
private void SaveToDataBase(string jpegPath)
{
    //jpegPath example is: (C:\Image.jpg)

    // Convert Image to binary
    var image = File.ReadAllBytes(jpegPath);

    string FilePath = Application.StartupPath + directory + dbName;
    string MDBConnStr = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + FilePath + "; Jet OLEDB:Engine Type=5";

    using (OleDbConnection connection = new OleDbConnection(MDBConnStr))
    {
        connection.Open();
        using (OleDbCommand command = new OleDbCommand("INSERT INTO Table JPGFile VALUES(?)", connection))
        {
            command.Parameters.Add("@Image", OleDbType.LongVarBinary).Value = image;
            command.ExecuteNonQuery();
        }
    }
}

但是请注意,OLEDB 中的二进制参数最多限制为 8000 字节。