Dot-Net
從 Access 數據庫中的附件欄位中提取文件
我們正在進行一個項目,我們需要將儲存在 Access 數據庫中的數據遷移到記憶體數據庫。Access 數據庫包含數據類型為
Attachment; 一些元組包含多個附件。我可以使用 獲取這些文件的文件名.FileName,但我不確定如何確定一個文件何時結束,另一個文件何時開始.FileData。我正在使用以下內容來獲取此數據:
System.Data.OleDb.OleDbCommand command= new System.Data.OleDb.OleDbCommand(); command.CommandText = "select [Sheet1].[pdf].FileData,* from [Sheet1]"; command.Connection = conn; System.Data.OleDb.OleDbDataReader rdr = command.ExecuteReader();
(我對這個問題的原始回答具有誤導性。它適用於隨後使用 Adobe Reader 打開的 PDF 文件,但它並不總是適用於其他類型的文件。以下是更正後的版本。)
不幸的是,我們無法
Attachment使用 OleDb 直接檢索 Access 欄位中的文件內容。.FileDataAccess 數據庫引擎將一些元數據添加到文件的二進制內容中,如果我們通過 OleDb檢索該元數據,則會包含該元數據。為了說明,使用 Access UI 將名為“Document1.pdf”的文件保存到附件欄位。該 PDF 文件的開頭如下所示:
如果我們使用以下程式碼嘗試將 PDF 文件提取到磁碟
using (OleDbCommand cmd = new OleDbCommand()) { cmd.Connection = con; cmd.CommandText = "SELECT Attachments.FileData " + "FROM AttachTest " + "WHERE Attachments.FileName='Document1.pdf'"; using (OleDbDataReader rdr = cmd.ExecuteReader()) { rdr.Read(); byte[] fileData = (byte[])rdr[0]; using (var fs = new FileStream( @"C:\Users\Gord\Desktop\FromFileData.pdf", FileMode.Create, FileAccess.Write)) { fs.Write(fileData, 0, fileData.Length); fs.Close(); } } }然後生成的文件將包含文件開頭的元數據(在這種情況下為 20 個字節)
Adobe Reader 能夠打開此文件,因為它足夠強大,可以忽略文件中可能出現在“%PDF-1.4”簽名之前的任何“垃圾”。不幸的是,並非所有文件格式和應用程序都對文件開頭的無關字節如此寬容。
從Access 中的欄位中提取文件的唯一Official™ 方法是使用ACE DAO對象的方法,如下所示:
Attachment``.SaveToFile``Field2// required COM reference: Microsoft Office 14.0 Access Database Engine Object Library // // using Microsoft.Office.Interop.Access.Dao; ... var dbe = new DBEngine(); Database db = dbe.OpenDatabase(@"C:\Users\Public\Database1.accdb"); Recordset rstMain = db.OpenRecordset( "SELECT Attachments FROM AttachTest WHERE ID=1", RecordsetTypeEnum.dbOpenSnapshot); Recordset2 rstAttach = rstMain.Fields["Attachments"].Value; while ((!"Document1.pdf".Equals(rstAttach.Fields["FileName"].Value)) && (!rstAttach.EOF)) { rstAttach.MoveNext(); } if (rstAttach.EOF) { Console.WriteLine("Not found."); } else { Field2 fld = (Field2)rstAttach.Fields["FileData"]; fld.SaveToFile(@"C:\Users\Gord\Desktop\FromSaveToFile.pdf"); } db.Close();請注意,如果您嘗試使用
.ValueField2 對象,您仍然會在字節序列的開頭獲得元數據;這個.SaveToFile過程就是把它剝離出來。

