SQLite - 如何从 XML 文件插入 JPG 图像(使用 Delphi 2009)

Posted

技术标签:

【中文标题】SQLite - 如何从 XML 文件插入 JPG 图像(使用 Delphi 2009)【英文标题】:SQLite - How to insert JPG image from XML file (using Delphi 2009) 【发布时间】:2015-11-28 14:43:23 【问题描述】:

我需要读取存储在 XML 文件中的 JPG 图像并将其插入到 SQLite 数据库中的 blob 字段中。

如下面的代码所示,我已经可以完成其中的一部分,但需要帮助才能将它们组合在一起。有人可以告诉我如何读取 XML 文件中的文本 bitmap 并将其插入到数据库中的 blob 字段中吗?

这是我已经可以做到的。

我可以使用 delphi XML 数据绑定单元读取 XML 文件,并使用以下(简化)代码将其中的文本内容存储在数据库中:

procedure TForm1.BtnReadXML(Sender: TObject);
 var
   sql : string;
   Data : XML_Binding_Photos.IXMLSuperStarReportType;  
   RecNum : integer;

begin
Data := XML_Binding_Photos.LoadSuperStarReport ('Photos.xml'); 
Database1.Open;
try
    RecNum := 2;
    SQL := 'INSERT INTO main.Photos ( id , firstname) VALUES ( Data.record_[RecNum].ID,  Data.record_[RecNum].Fname ) ;' ;
    Query1.Close;
    Query1.selectSQL := sql; //insert the data
    Query1.Open ;
finally
    Database1.Close;
end;
end;

我还可以使用如下流将光盘中的 JPG 图像插入数据库:

procedure TForm1.Insert_JPG_PhotoFromFile(Sender: TObject);
var 
    strm : TmemoryStream ;
begin
Database1.Open;
strm := TmemoryStream.Create;
try
    strm.LoadFromFile('C:\...\testpic2.jpg');
    Query1.Close;
    Query1.selectSQL := ('INSERT INTO main.Photos (id, photo) VALUES (''999'', :photo)');
    Query1.Params.ParamByName('photo').LoadFromStream(Strm,ftGraphic);
    Query1.Open ;
finally
    strm.Free ;
    DISQLite3Database1.close;
end;
end; 

但是我的XML文件里面有一张JPG图片,编码如下:

 <Record>
    <ID>14046</ID>
    <Fname>Fred</Fname>
    <Photo>/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAE  - lots more of the same - txNxvd8dc44Htz/Ktx3Oe3T/AB96KK6DA//Z </Photo> 
  </Record>  

我可以使用 XML 数据绑定单元将构成位图的字符读入字符串或 StringStream,但似乎无法将其正确保存为数据库中的 blob。

(我不想先将每个 XML 图像以 jpg 格式保存到光盘中,部分原因是它已经以不同的形式保存在光盘上,部分原因是 xml 文件中有数千张此类图像。此外,出于其他原因,我确实想将图像放在数据库中,而不是将其放在磁盘上并仅存储文件名)

【问题讨论】:

您知道如何从文件中获取流以及如何将流存储到数据库中。因此,您的真正问题可以简化为:如何将图像数据从 xml 获取到流中。也许这个真正的问题会引导你找到答案;o) 经过更多调查,数据可能是 base64 编码的,可能是 jpg 而不是 bmp。我使用了 Indy 组件 TIdDecoderMIME 即 PhotoData := IdDecoderMIME1.DecodeString(PhotoData);然后查看十六进制的结果,它以 FFD8 开头,我理解这意味着它是 jpg。所以我尝试使用 TheStream.Write(PhotoData[1], Length(PhotoData)) 制作一个流;其次是 Query1.Params.ParamByName('the_photo').LoadFromStream(TheStream,ftGraphic);但我仍然没有在数据库中得到正确的图像(那里有一张图像,但只有彩色框和奇怪的符号 Base64 字符串是编码流。只需寻找一个 base64 字符串来流式解码器;o) "只需寻找一个 base64 字符串来流式解码器" ? ?但我想我已经在解码 XML 中的 base64 字符串了。那不是 PhotoData := IdDecoderMIME1.DecodeString(PhotoData);做?那个“看起来”像 jpg 的字节的输出,即它们以十六进制 FFD8 开头 是的,但您没有使用结果流。你使用了base64编码的字符串TheStream.Write(PhotoData[1], Length(PhotoData)) ; 【参考方案1】:

这适用于从 XLM 文件中获取图像并将其插入到 blob 字段中的 sqlite 数据库中。

此代码使用 XML 数据绑定单元来简化从 xml 文件中读取 base64 编码图像作为字符串,存储在 Base64PhotoData 中。 然后它使用我放在表单上的 Indy TIdDecoderMIME 组件 (IdDecoderMIME1: TIdDecoderMIME) 将 base64 解码为 Tbytes 类型的变量(称为 DecodeBytes) 然后,要将字节数组存储在 blob 字段中,每个字节都需要转换回十六进制,并且整个内容都以“x”开头,表示它是十六进制。 此解决方案不需要流(尽管如果该方法更好,它可能会被转换为这样做)

(所有的引号都是单引号)

Procedure TForm1.btnimportphotosfromxmlClick(Sender: TObject);
 var
   sql : string;
   XMLData : XML_Binding_Photos.IXMLStarReportType;  //in  unit  XML_Binding_Photos
   i : integer;
   Base64PhotoData, DecodedPhotoData : ansistring;
   DecodeBytes: TBytes;
   PhotoBlobs : string;
begin
XMLData := XML_Binding_Photos.LoadStarReport ('Photos.xml');       //open xml as a IXMLStarReportType , created from the xml file with the XML data binding wizard
Base64PhotoData := SIMSData.record_[2].Photo;                          //get the xml photo data from xml file, in this test case the second record
DecodeBytes := IdDecoderMIME1.DecodeBytes(Base64PhotoData) ;  //decode base64 charater string to an array of bytes

PhotoBlobs := '';                                           //initialsise the string we are going to insert into the blob field
for i  := 0 to high(DecodeBytes) do                //convert each byte to a hex charater so that it can be inserted into a blob
            PhotoBlobs := PhotoBlobs + inttohex(DecodeBytes[i],2);

SQL := ''
+'INSERT '
+'INTO   StudentPhotos ( id, photo  ) '
+'       VALUES  ( ''777'',   '
+'              x''' + PhotoBlobs +''') ' ;                         // note the prepending of lower case x to the hex byte string


DISQLite3Database1.DatabaseName := 'C:\...\testphoto.db';
DISQLite3Database1.open
try
   DISQLite3Database1.Execute(sql);
finally
  DISQLite3Database1.close;
end;

【讨论】:

有一个类叫做TBytesStream,你会从TBytes得到一个流,见docwiki.embarcadero.com/Libraries/en/… 谢谢,我会调查一下,虽然我不确定使用蒸汽会对这个答案产生什么影响。

以上是关于SQLite - 如何从 XML 文件插入 JPG 图像(使用 Delphi 2009)的主要内容,如果未能解决你的问题,请参考以下文章

Android SQLite 数据库:插入速度慢

如何使用本机 sqlite 库而不是 QSql 从 sqlite 插入和检索 QString

从Excel文件到SQLite数据库的SQLite插入循环

如何使用 PHP(和 HTML)从 SQLite 中选择、插入、更新和删除数据

如何使用通用函数将数据插入 sqlite 数据库

从 JSONArray 插入/更新 +10000 行到 SqLite 时如何防止应用程序崩溃