I'm having a problem writing large amounts of data to FILESTREAM column on SQL Server. Specifically, smallish files around 1.5-2GB are handled fine, but when the size reaches 6GB and up, I'm getting intermittent IOException
"The handle is invalid" on .CopyTo()
towards the end of the transfer.
I've thought about writing the data in chunks, but SQL Server copies the backing file for the field before allowing to append data to it, which destroys the performance for large files completely.
Here's the code:
public long AddFragment (string location , string description = null)
{
const string sql =
@"insert into [Fragment] ([Description],[Data]) " +
"values (@description,0x); " +
"select [Id], [Data].PathName(), " +
"GET_FILESTREAM_TRANSACTION_CONTEXT() " +
"from " +
"[Fragment] " +
"where " +
"[Id] = SCOPE_IDENTITY();";
long id;
using (var scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions {
Timeout = TimeSpan.FromDays(1)
}))
{
using (var connection = new SqlConnection(m_ConnectionString))
{
connection.Open();
byte[] serverTx;
string serverLocation;
using (var command = new SqlCommand (sql, connection))
{
command.Parameters.Add("@description",
SqlDbType.NVarChar).Value = description;
using (var reader = command.ExecuteReader ())
{
reader.Read();
id = reader.GetSqlInt64(0).Value;
serverLocation = reader.GetSqlString (1).Value;
serverTx = reader.GetSqlBinary (2).Value;
}
}
using (var source = new FileStream(location, FileMode.Open,
FileAccess.Read, FileShare.Read, 4096,
FileOptions.SequentialScan))
using (var target = new SqlFileStream(serverLocation,
serverTx, FileAccess.Write))
{
source.CopyTo ( target );
}
}
scope.Complete();
}
return id;
}
A FILESTREAM filegroup is a special filegroup that contains file system directories instead of the files themselves. These file system directories are called data containers. Data containers are the interface between Database Engine storage and file system storage.
FileStream and FileTable are features of SQL Server for storing unstructured data in SQL Server alongside other data. The FileStream feature stores unstructured data in the file system and keeps a pointer of the data in the database, whereas FileTable extends this feature even further allowing non-transactional access.
Click on 'Add FileGroup' in the FILESTREAM section and specify the name of the SQL Server FILESTREAM filegroup. Click 'OK' to create the database with this new filegroup. Once the database is created, open the database properties to add the file in the newly created 'DemoFileStream' filegroup.
Enabling FILESTREAM Right-click the instance, and then click Properties. In the SQL Server Properties dialog box, click the FILESTREAM tab. Select the Enable FILESTREAM for Transact-SQL access check box. If you want to read and write FILESTREAM data from Windows, click Enable FILESTREAM for file I/O streaming access.
I would suggest you use BufferedStream Class around your FileStream class.
Also make sure you are setting the WriteTimeOut property on the SqlFileStream class.
Here you find a really good post that explain everything about SqlFileStream http://www.simple-talk.com/sql/learn-sql-server/an-introduction-to-sql-server-filestream/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With