Introduction
AccessBlob illustrates how to upload and download Binary Large OBjects (BLOB) to a Microsoft Access database. The simplest way of describing a BLOB is as a file stored in a field in a relational database. A BLOB may be an image file, a spreadsheet, a word processor file, etc. There are many code snippets on the web for uploading and downloading BLOBs to SQL Server, but I could not find anything for Microsoft Access.
The sample application included with this article is just used to illustrate how to upload and download BLOB data to a Microsoft Access database. The sample application comes with a Microsoft Access 2000 database. When you use the application, the text box for the Data File contains the full path name to the file on your disk. This field is used for the file that you want to upload and for the file that you want to download. When you download, you must also select the file that you want to download from the listview.
Background
Microsoft Access stores BLOB data in the a field with an OLE Object data type (if you are creating the table from Design View). If you are creating the table from a SQL statement, the data type is IMAGE
(similar to SQL Server). For this example application, the following Access table is used.
CREATE TABLE File (
FileName VARCHAR(255),
Size INT,
Type VARCHAR(255),
DateUploaded DATETIME,
File IMAGE,
CONSTRAINT File_PK PRIMARY KEY(FileName)
)
Upload the File
The file is uploaded by assigning a memory resident version of the file to a parameter of the OleDbCommand
object. The file is loaded into memory using a BinaryReader
object because we do not want a reader to process any of the data. The BinaryReader
's constructor cannot take a file name, so we must create a FileStream
first and pass that to the BinaryReader
's constructor.
The variables that we are using are:
System.Data.OleDb.OleDbConnection conn = null;
System.Data.OleDb.OleDbCommand cmd = null;
System.Data.OleDb.OleDbDataReader dr = null;
System.Data.OleDb.OleDbParameter param = null;
System.IO.FileStream fileStream;
System.IO.BinaryReader reader = null;
byte[] data = null;
We need to get the file name, type, and date that the file was uploaded. The following code does this for us.
string[] arr = DataFile.Text.Split(new char[]{'\\'});
string fileName = arr[arr.Length - 1];
arr = DataFile.Text.Split(new char[]{'.'});
string type = (arr.Length > 1) ? arr[arr.Length - 1] : "";
string dateUploaded = System.DateTime.Now.ToShortDateString() +
" " + System.DateTime.Now.ToShortTimeString();
int numRecords = 0;
The rest of the procedure is to:
- Load the file into memory,
- Open a connection to the database,
- Determine if the record already exists; if the record does not exist, we add the record without the BLOB data, and finally
- Update the record with the BLOB data. Please note that the BLOB data is passed via the parameter.
You may find that it is odd that we add the record and then update the BLOB data. This was the only way that I was able to get the BLOB data into the database. I was not able to get the BLOB data into the database using the INSERT
statement. The code is:
fileStream = new System.IO.FileStream(DataFile.Text,
System.IO.FileMode.Open, System.IO.FileAccess.Read);
reader = new System.IO.BinaryReader(fileStream);
data = reader.ReadBytes((int)fileStream.Length);
conn = new System.Data.OleDb.OleDbConnection("Provider=" +
"Microsoft.Jet.OLEDB.4.0;Data Source=" + AccessFile.Text);
conn.Open();
cmd = new System.Data.OleDb.OleDbCommand("SELECT " +
"COUNT(*) FROM [File] WHERE [FileName]='" + fileName + "'",conn);
dr = cmd.ExecuteReader();
dr.Read();
numRecords = dr.GetInt32(0);
dr.Close();
if(numRecords == 0) {
cmd = new System.Data.OleDb.OleDbCommand("INSERT INTO" +
" [File] ([FileName],[Size],[Type]," +
"[DateUploaded]) VALUES('" + fileName + "'," +
data.Length + ",'" + type + "', #"+
dateUploaded + "#)",conn);
cmd.ExecuteNonQuery();
}
cmd = new System.Data.OleDb.OleDbCommand("UPDATE [File] " +
"SET [File]=@file, [Size]=" + data.Length +
", [DateUploaded]=#" + dateUploaded +
"# WHERE [FileName]='" + fileName + "'",conn);
param = cmd.Parameters.Add("@file",
System.Data.OleDb.OleDbType.Binary);
param.Value = data;
cmd.ExecuteNonQuery();
Download the File
When the file is downloaded, the file is read from the database into a buffer, then the buffer is written to the disk. Because we are working with raw binary data, we use the BinaryWriter
to write the data. The BinaryWriter
's constructor cannot take a file name, so we must create a FileStream
first and pass that to the BinaryWriter
's constructor.
The variables that we are using to download the file are:
System.Data.OleDb.OleDbConnection conn = null;
System.Data.OleDb.OleDbCommand cmd = null;
System.Data.OleDb.OleDbDataReader reader = null;
System.IO.FileStream fileStream = null;
System.IO.BinaryWriter writer = null;
int bufferSize = 1000;
byte[] buffer = new byte[bufferSize];
long startIndex = 0;
long numberOfBytes = 0;
The core of the download code is:
conn = new System.Data.OleDb.OleDbConnection("Provider" +
"=Microsoft.Jet.OLEDB.4.0;Data Source=" + AccessFile.Text);
cmd = new System.Data.OleDb.OleDbCommand("SELECT [File] " +
"FROM [File] WHERE [FileName] = '" +
FileListView.SelectedItems[0].Text + "'", conn);
conn.Open();
reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
reader.Read();
fileStream = new System.IO.FileStream(DataFile.Text,
System.IO.FileMode.OpenOrCreate,
System.IO.FileAccess.Write);
writer = new System.IO.BinaryWriter(fileStream);
do {
numberOfBytes = reader.GetBytes(0,
startIndex, buffer, 0, bufferSize);
if(numberOfBytes == 0) {
break;
}
writer.Write(buffer, 0, (int) numberOfBytes);
startIndex += numberOfBytes;
} while (true);
writer.Flush();
Conclusion
AccessBlob demonstrates how to upload and download BLOB data to and from a Microsoft Access database. You can also upload and download BLOB data using an OleDbDataAdapter
and a DataSet
. If you are familiar with using OleDbDataAdapter
s, you should have no problem converting this code to use OleDbDataAdapter
s and DataSet
s. I personally find using OleDbDataAdapter
s cumbersome, and prefer to keep my code simple by just using OleDbCommand
objects.