Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 从Access数据库中的附件字段提取文件_.net_Database_Ms Access - Fatal编程技术网

.net 从Access数据库中的附件字段提取文件

.net 从Access数据库中的附件字段提取文件,.net,database,ms-access,.net,Database,Ms Access,我们正在进行一个项目,需要将Access数据库中存储的数据迁移到缓存数据库。Access数据库包含数据类型为附件的列;某些元组包含多个附件。我可以通过使用.FileName获取这些文件的文件名,但我不确定如何在.FileData中确定一个文件何时结束,另一个文件何时开始 我使用以下方法获取此数据: System.Data.OleDb.OleDbCommand command= new System.Data.OleDb.OleDbCommand(); command.CommandText =

我们正在进行一个项目,需要将Access数据库中存储的数据迁移到缓存数据库。Access数据库包含数据类型为附件的列;某些元组包含多个附件。我可以通过使用
.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文件有效,但对其他类型的文件并不总是有效。以下是更正的版本。)

不幸的是,我们无法使用OleDb直接检索Access
附件
字段中的文件内容。Access数据库引擎将一些元数据预先添加到文件的二进制内容中,如果我们通过OleDb检索
.FileData
,则会包含这些元数据

举例来说,名为“Document1.pdf”的文档使用Access UI保存到附件字段中。该PDF文件的开头如下所示:

如果我们使用以下代码尝试将PDF文件解压缩到磁盘

使用(OleDbCommand cmd=new OleDbCommand())
{
cmd.Connection=con;
cmd.CommandText=
“选择Attachments.FileData”+
“来自附件测试”+
“WHERE Attachments.FileName='Document1.pdf';
使用(OleDbDataReader rdr=cmd.ExecuteReader())
{
rdr.Read();
字节[]文件数据=(字节[])rdr[0];
使用(var fs=newfilestream)(
@“C:\Users\Gord\Desktop\FromFileData.pdf”,
FileMode.Create,FileAccess.Write)
{
写入(fileData,0,fileData.Length);
fs.Close();
}
}
}
然后,生成的文件将在文件的开头包含元数据(本例中为20字节)

Adobe Reader能够打开此文件,因为它足够强大,可以忽略文件中“%PDF-1.4”签名之前可能出现的任何“垃圾邮件”。不幸的是,并不是所有的文件格式和应用程序都能在文件的开头原谅多余的字节

仅为官方™ 从Access中的
附件
字段提取文件的方法是使用ACE DAO
字段2
对象的
.SaveToFile
方法,如下所示:

//必需的COM引用:Microsoft Office 14.0 Access数据库引擎对象库
//
//使用Microsoft.Office.Interop.Access.Dao。。。
var dbe=new DBEngine();
Database db=dbe.OpenDatabase(@“C:\Users\Public\Database1.accdb”);
记录集rstMain=db.OpenRecordset(
“从AttachTest中选择附件,其中ID=1”,
RecordsetTypeEnum.dbOpenSnapshot);
Recordset2 rstatach=rstMain.Fields[“附件”].Value;
而((!“Document1.pdf”.Equals(rstAttach.Fields[“FileName”].Value))&&(!rstAttach.EOF))
{
rstatach.MoveNext();
}
if(rstAttach.EOF)
{
Console.WriteLine(“未找到”);
}
其他的
{
Field2 fld=(Field2)rstatach.Fields[“FileData”];
fld.SaveToFile(@“C:\Users\Gord\Desktop\FromSaveToFile.pdf”);
}
db.Close();

请注意,如果您尝试使用Field2对象的
.Value
,您仍将在字节序列的开头获得元数据;
.SaveToFile
过程就是将其剥离出来的过程。

我花了一些时间拼凑信息,从附件字段中检索存储的文件,所以我想我应该共享它

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.IO;
using System.Diagnostics;

namespace AttachCheck
{
    public partial class Form1 : Form
    {
        DataSet Set1 = new DataSet();
        int ColId;

        public Form1()
        {
            InitializeComponent();

            OleDbConnection connect = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source='db/Adb.accdb'"); //set up connection
            //CL_ID is a fk so attachments can be linked to users
            OleDbCommand sql = new OleDbCommand("SELECT at_ID, [at_Name].[FileData], [at_Name].[FileName], [at_Name].[FileType] FROM Attachments WHERE at_ID =1;", connect);
            //adding sql to addapter to be ran

            OleDbDataAdapter OleDA = new OleDbDataAdapter(sql);
            //attempting to open connection
            try { connect.Open(); }
            catch (Exception err) { System.Console.WriteLine(err); }

            
            OleDA.Fill(Set1); //create and fill dataset
            connect.Close();for (int i = 0; i < Set1.Tables[0].Rows.Count; i++)
            {
                System.Console.WriteLine(Set1.Tables[0].Rows[i]["at_Name.FileName"].ToString() + "This is the file name");


            // by using a datagrid it allows you to display the attachments and select which to open, the open should be a button.
            dataGridView1.Rows.Add(new object[] { Set1.Tables[0].Rows[i]["at_ID"].ToString(), Set1.Tables[0].Rows[i]["at_Name.FileName"].ToString(), "Open" });
            }
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

            DataGridViewCell cell = (DataGridViewCell)
            dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];

            System.Console.WriteLine(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]);
            string FullRow = dataGridView1.Rows[e.RowIndex].ToString(); //data retrieved from click on datagrid 
            //need to sub string to cut away row index and leave number
            string SubRow = FullRow.Substring(24, 1); //cutting string down from position 24 for 1 character

            System.Console.WriteLine(SubRow + " This is Row"); //

            int RowId = int.Parse(SubRow); //turn row number from string into integer that can be used

            string FullRow2 = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].ToString(); //data retrieved from click on datagrid 
            //need to sub string to cut away row index and leave number
            string SubRow2 = FullRow2.Substring(37, 1); //cutting string down from position 24 for 1 character
            System.Console.WriteLine(SubRow2 + " This is Column"); //
            int ColId = int.Parse(SubRow2); //turn row number from string into integer that can be used

            
            if (ColId == 2)
            {
                string fileName = Set1.Tables[0].Rows[RowId]["at_Name.FileName"].ToString(); //assign the file to variable

                //retrieving the file contents from the database as an array of bytes
                byte[] fileContents = (byte[])Set1.Tables[0].Rows[RowId]["at_Name.FileData"];


                fileContents = GetFileContents(fileContents); //send filecontents array to be decrypted

                string fileType = Set1.Tables[0].Rows[RowId]["at_Name.FileType"].ToString();


                DisplayTempFile(fileName, fileContents, fileType); //forward the file type to display file contents   
            }
        }

        private const int CONTENT_START_INDEX_DATA_OFFSET = 0; //values used for decoding 
        private const int UNKNOWN_DATA_OFFSET = 4; //the files
        private const int EXTENSION_LENGTH_DATA_OFFSET = 8; //storedw within the access database
        private const int EXTENSION_DATA_OFFSET = 12; //and this one


        private byte[] GetFileContents(byte[] fileContents)
        {

            int contentStartIndex = BitConverter.ToInt32(fileContents, CONTENT_START_INDEX_DATA_OFFSET);

            //'The next four bytes represent a value whose meaning is unknown at this stage, although it may represent a Boolean value indicating whether the data is compressed or not.
            int unknown = BitConverter.ToInt32(fileContents, UNKNOWN_DATA_OFFSET);

            //'The next four bytes contain the the length, in characters, of the file extension.
            int extensionLength = BitConverter.ToInt32(fileContents, EXTENSION_LENGTH_DATA_OFFSET);

            //'The next field in the header is the file extension, not including a dot but including a null terminator.
            //'Characters are Unicode so double the character count to get the byte count.
            string extension = Encoding.Unicode.GetString(fileContents, EXTENSION_DATA_OFFSET, extensionLength * 2);
            return fileContents.Skip(contentStartIndex).ToArray();


        }


        private void DisplayTempFile(string fileName, byte[] fileContents, string fileType)
        {

            // System.Console.WriteLine(fileName + "File Name");
            // System.Console.WriteLine(fileType + "File Type");
            // System.Console.WriteLine(fileContents + "File Contents");
            
            string tempFolderPath = Path.GetTempPath(); //creating a temperary path for file to be opened from
            string tempFilePath = Path.Combine(tempFolderPath, fileName); // assigning the file to the path

            if (!string.IsNullOrEmpty(tempFilePath)) //checking the temp file exists
            {
                tempFilePath = Path.Combine(tempFolderPath, //combines the strings 0 and 1 below
                String.Format("{0}{1}",
                Path.GetFileNameWithoutExtension(fileName),      //0                                                    
                Path.GetExtension(fileName))); //1
            }

            //System.Console.WriteLine(tempFolderPath + " tempFolderPath");
            //System.Console.WriteLine(tempFilePath + " tempFilePath");

            //'Save the file and open it.
            File.WriteAllBytes(tempFilePath, fileContents);
            //creates new file, writes bytes array to it then closes the file
            //File.ReadAllBytes(tempFilePath);

            //'Open the file.
            System.Diagnostics.Process attachmentProcess = Process.Start(tempFilePath);
            //chooses the program to open the file if available on the computer

        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
使用System.Data.OleDb;
使用System.IO;
使用系统诊断;
名称空间附加检查
{
公共部分类Form1:Form
{
数据集Set1=新数据集();
int-ColId;
公共表格1()
{
初始化组件();
OleDbConnection connect=new-OleDbConnection(“Provider=Microsoft.ACE.OLEDB.12.0;Data Source='db/Adb.accdb');//设置连接
//CL_ID是fk,因此附件可以链接到用户
OleDbCommand sql=新OleDbCommand(“从附件中选择at_ID、[at_Name].[FileData]、[at_Name].[FileName]。[FileName]。[at_Name]。[FileType],其中at_ID=1;”,连接);
//将sql添加到要运行的addapter
OleDbDataAdapter OleDA=新的OleDbDataAdapter(sql);
//正在尝试打开连接
尝试{connect.Open();}
catch(异常错误){System.Console.WriteLine(错误);}
OleDA.Fill(Set1);//创建和填充数据集
connect.Close();for(int i=0;i