Академический Документы
Профессиональный Документы
Культура Документы
SQL Server's new FILESTREAM feature simplifies the process of keeping file-based
data, such as images, in sync with relational data.
by Thiru Thangarathinam
early all applications require some sort of data integration—at minimum, retrieving some data and
displaying it in the user interface. Usually, an application uses a combination of structured and
unstructured data, which introduces a number of challenges. Often, you have to create, update, delete, and
read these disparate data types within a single transaction—and that's difficult when the structured data
resides in a relational database but the unstructured data resides in a file system. SQL Server 2008's new
FILESTREAM feature helps solve this disjunct data problem by letting you store unstructured data in the file
system while still preserving the transactional integrity of that data. This article explores the FILESTREAM
feature and showcases how you can leverage it to gain more control over your own unstructured data.
With SQL Server 2005, when building an application that relies on both structured (relational) data and
unstructured (non-relational) data, you had a couple of options:
• Store the relational data in the database and the non-relational data in a dedicated storage such as file
systems and file servers. Although this approach can be cost-effective, it introduces additional
complexity, because you need to manage the transactional integrity across both relational and non-
relational systems.
• Store both relational and non-relational data in the database. For many years, databases have
supported storage of non-relational data as Binary Large Objects, or BLOBs. SQL Server calls this data
type a varbinary column. Although storing such data in the database is convenient, it typically comes at
a higher cost (in disk space and storage/retrieval time) and can negatively impact the overall
performance of the application.
However, with SQL Server 2008, the new FILESTREAM attribute combines with a varbinary column, so you
can store the actual data on the server's file system while managing and accessing it within the context of the
database. The feature also gives SQL Server the capability of maintaining the integrity not only between
records in the database but also between database records and external files associated with those records.
Because this feature is implemented as just a new attribute of the existing varbinary(max) data type,
developers can easily take advantage of FILESTREAM without having to completely re-architect their
applications.
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009
Managing Files with SQL Server 2008's FILESTREAM Feature Page 2 of 7
You should consider using FILESTREAM when any of the following conditions are true:
Enabling FILESTREAM
By default, the FILESTREAM feature is disabled, so before you can use it, you must configure both the server
and database instances using the following steps:
• 0—Disables FILESTREAM support for this instance. This is the default value.
• 1—Enables FILESTREAM for Transact-SQL access.
• 2—Enables FILESTREAM for Transact-SQL and Win32 streaming access.
After completing the server and database instance configurations, the next step is to create the actual
database in which the data will reside. Because FILESTREAMs are specifically created for storing binary data
in file systems, you use the CREATE DATABASE statement to create a special FILEGROUP and mark it as a
stream:
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009
Managing Files with SQL Server 2008's FILESTREAM Feature Page 3 of 7
Next, create a table, designating one of its columns as type VARBINARY(MAX) FILESTREAM:
The preceding table definition assigns the Picture column as the varbinary(max) column, with the
FILESTREAM attribute enabled. Note that the table with a FILESTREAM column must have at least one non-
null unique ROWGUID column.
Any binary data you store inside the Picture column is not accessible from the file system; the only way to work
with this binary data is through the standard CRUD (INSERT, UPDATE, and DELETE) SQL statements. The
following example inserts a single row into the Product table.
GO
That inserts a new row where the ProductID is 1, the Name contains Bicycle, the Picture column value is
NULL, and the RowGuid column contains some default GUID value. Now you can retrieve this row from a .NET
application, and read, overwrite, or append to its contents.
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009
Managing Files with SQL Server 2008's FILESTREAM Feature Page 4 of 7
For this example, consider a simple scenario that takes some user input, converts that into a byte array, and
stores the information in the Picture column of the Product table. To follow along, create a Visual C# Windows
Application named FileStreamExample. To the new project's default form, add a Button named btnWriteFile, a
TextBox named txtInput and a ListBox named lstResults. After that, double-click on the button to create a Click
event handler containing the code shown in Listing 1, which begins by retrieving the connection string from
app.config using the ConfigurationManager.ConnectionStrings property:
Next it opens a connection to the database, and assigns appropriate values to the SqlCommand object to
retrieve the Products table row where ProductID is 1:
command.Connection = connection;
//Get the PathName of the File from the database
command.CommandText = "SELECT Picture.PathName(), "
+ "GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Product "
+ "WHERE ProductID = 1";
So, the code creates a new SqlTransaction object by calling the SqlConnection.BeginTransaction() method and
assigning it to the SqlCommand object:
SqlTransaction transaction =
connection.BeginTransaction(IsolationLevel.ReadCommitted);
command.Transaction = transaction;
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009
Managing Files with SQL Server 2008's FILESTREAM Feature Page 5 of 7
At this point, Listing 1 invokes the ExecuteReader() method, executing the SQL statement. After executing the
query, it retrieves the path of the file stream and assigns it to a local variable:
You need a stream to write to a file, so the next step is to create an instance of the SqlFileStream class,
supplying the path, transaction context, file access enumeration, file options enumeration, and allocation size:
The SqlFileStream class is a new class (introduced with SQL Server 2008) that provides access to
FILESTREAM column data as a sequence of bytes. Table 1 provides a brief description of the properties
exposed by the SqlFileStream class.
Table 1. SqlFileStream Class Properties: The table lists and describes the properties exposed by the
SqlFileStream class.
Property Description
Name Returns the logical path of the SqlFileStream object that is supplied to the constructor.
TransactionContext Allows you to specify the transaction context associated with the SqlFileStream object.
Length Returns the length of the current stream in bytes.
Position Allows you to specify the position within the current stream.
ReadTimeout Specified in milliseconds, this property determines the timeout period for the stream at the
time of reading.
WriteTimeout Specified in milliseconds, this property determines the timeout period for the stream at the
time of writing.
Next, Listing 1 retrieves the user input, converts that to a byte array, and writes that to the file stream.
transaction.Commit();
That's the basic process for writing to a database-managed file using the FILESTREAM feature. Now that you
know how to write to a FILESTREAM column, reading from the column will be simpler.
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009
Managing Files with SQL Server 2008's FILESTREAM Feature Page 6 of 7
To the C# project's default form, add a Button named btnReadFile, and paste the code in Listing 2 into its Click
event:
For brevity, I'll only discuss the code that differs from the previous section. When you create the SqlFileStream,
you need to indicate that you are opening the file stream for read-only access with SequentialScan enabled.
After that, read the contents of the file stream into a byte array, convert that into a string, and display it in the
ListBox.
When you run the application, you'll see a screen similar to that shown in
Figure 2 (you'll see more about the Append File button in the next
section). When you click the "Write File" button, the application writes the
contents of the TextBox to the file stream. When you click the "Read File"
button, the application reads the contents from the file stream and
displays that in the ListBox.
So far, you have seen how to read and write to a file stream. The next
example shows the code required to append to an existing file stream in
the database. Figure 2. Sample Project: At this
point, you can read and write user-
entered data by setting and reading
Using FILESTREAM to Append Data the contents of the FILESTREAM
column using the SqlFileStream
Add a command button named btnAppendFile and modify its Click event Class.
handler as shown in Listing 3:
This time, when you instantiate the SqlFileStream object, you set the file access enumeration to ReadWrite, so
you can both read from and write to the file stream.
You then move the file stream pointer to the end of the file so that you can append to it.
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009
Managing Files with SQL Server 2008's FILESTREAM Feature Page 7 of 7
stream.Seek(0, SeekOrigin.End);
Then, write the user input to the file stream using the SqlFileStream.Write() method.
stream.Write((System.Text.Encoding.ASCII.GetBytes
(contents)), 0, contents.Length);
Advantages of FILESTREAM
That's the entire process. You can now read, write, and append data to a database-managed file. Although the
process may be slightly more complex than using files or storing data directly in BLOBs, you'll find that letting
the database manage file storage has several advantages:
• You can access both relational and non-relational data using a single data store.
• SQL Server automatically includes the non-relational data (BLOB) during database backups and
restores.
• There is no file size limitation. The 2GB maximum size limitation for a varbinary(max) column doesn't
apply to FILESTREAM; you are limited only by the available space on the NTFS file system.
• You can insert, update, and delete both relational and non-relational data within a single transaction.
• Using FILESTREAM is very efficient, because SQL Server doesn't use buffer pool memory to operate
on non-relational (BLOBs) data (as is the case with traditional BLOB columns).
• You can access non-relational data directly from within middle tier .NET code using ADO.NET without
having to resort to a separate API.
• Depending on the size of the file, the NTFS file system can save and retrieve large BLOBs faster than
SQL Server.
The examples in this article showed how to implement the new FILESTREAM feature. As you can see,
FILESTREAM provides an easy-to-use transaction programming model when you want to store both relational
and non-relational data in a single transaction.
Thiru Thangarathinam works at Intel Corporation in Chandler, Arizona. He's a Microsoft MVP who specializes
in architecting, designing, and developing distributed enterprise-class applications using .NET-related
technologies. He is the author of the books 'Professional ASP.NET 2.0 XML' and 'Professional ASP.NET 2.0
Databases' from Wrox press and has coauthored a number of books on .NET-related technologies. He is a
frequent contributor to leading technology-related online publications.
http://www.devx.com/dotnet/Article/40812/1954?pf=true 10/22/2009