Managing FILESTREAM Data Win32
Managing FILESTREAM Data Win32
Note:
The examples in this topic require the FILESTREAM-enabled database and table that are created in
How To: Create a FILESTREAM-Enabled Database [ http://msdn.microsoft.com/en-
us/library/cc645585.aspx ] and How to: Create a Table for Storing FILESTREAM Data
[ http://msdn.microsoft.com/en-us/library/cc645583.aspx ] .
Each cell in a FILESTREAM table has a file path that is associated with it. To read the path, use the
PathName property of a varbinary(max) column in a Transact-SQL statement. The following example
shows how to read the file path of a varbinary(max) column.
Copy Code
PRINT @filepath
Copy Code
BEGIN TRANSACTION
SELECT @txContext = GET_FILESTREAM_TRANSACTION_CONTEXT()
PRINT @txContext
COMMIT
To obtain a Win32 file handle, call the OpenSqlFilestream API. This API is exported from the sqlncli.dll
file. The returned handle can be passed to any of the following Win32 APIs: ReadFile
[ http://go.microsoft.com/fwlink/?LinkId=86422 ] , WriteFile [ http://go.microsoft.com/fwlink/?
LinkId=86423 ] , TransmitFile [ http://go.microsoft.com/fwlink/?LinkId=86424 ] , SetFilePointer
[ http://go.microsoft.com/fwlink/?LinkId=86425 ] , SetEndOfFile [ http://go.microsoft.com/fwlink/?
LinkId=86426 ] , or FlushFileBuffers [ http://go.microsoft.com/fwlink/?LinkId=86427 ] . The following
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 2 of 9
examples show you how to obtain a Win32 File handle and use it to read and write data to a FILESTREAM
BLOB.
using System.IO;
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
namespace FILESTREAM
{
class Program
{
static void Main(string[] args)
{
SqlConnection sqlConnection = new SqlConnection(
"Integrated Security=true;server=(local)");
try
{
sqlConnection.Open();
sqlCommand.CommandText =
"SELECT Chart.PathName()"
+ " FROM Archive.dbo.Records"
+ " WHERE SerialNumber = 3";
sqlCommand.CommandText =
"SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()";
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 3 of 9
int numBytes = 0;
sqlFileStream.Write(unicode.GetBytes(someData.ToCharArray()),
0,
someData.Length);
sqlFileStream.Seek(0L, SeekOrigin.Begin);
if (numBytes != 0)
Console.WriteLine(readData);
//The final step is to commit or roll back the read and write
//operations that were performed on the FILESTREAM BLOB.
sqlCommand.Transaction.Commit();
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
sqlConnection.Close();
}
return;
}
}
}
Imports System.IO
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Data
Imports System.Data.SqlClient
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 4 of 9
Imports System.Data.SqlTypes
Module Module1
Public Sub Main(ByVal args As String())
' Dim sqlConnection As New SqlConnection("Integrated Security=true;serve
r=(local)")
Dim sqlConnection As New SqlConnection("Integrated Security=true;server=kellyre
yue\MSSQL1")
Try
sqlConnection.Open()
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 5 of 9
sqlFileStream.Write(unicode.GetBytes(someData.ToCharArray()), 0, someData.L
ength)
sqlFileStream.Seek(0, SeekOrigin.Begin)
'The final step is to commit or roll back the read and write
'operations that were performed on the FILESTREAM BLOB.
sqlCommand.Transaction.Commit()
Catch ex As System.Exception
Console.WriteLine(ex.ToString())
Finally
sqlConnection.Close()
End Try
Return
End Sub
End Module
#include <windows.h>
#include <sql.h>
#include<sqltypes.h>
#include<sqlext.h>
#include <stdio.h>
#include <sqlncli.h>
/// <summary>
///This class iterates though the ODBC error queue and prints all of the
///accumulated error messages to the console.
/// </summary>
class ODBCErrors
{
private:
int m_iLine; //Source code line on which the error occurred
SQLSMALLINT m_type; //Type of handle on which the error occurred
SQLHANDLE m_handle; //ODBC handle on which the error occurred
public:
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 6 of 9
/// <summary>
///Default constructor for the ODBCErrors class
///</summary>
ODBCErrors()
{
m_iLine = -1;
m_type = 0;
m_handle = SQL_NULL_HANDLE;
}
/// <summary>
///Constructor for the ODBCErrors class
/// </summary>
/// <param name="iLine">
/// This parameter is the source code line
/// at which the error occurred.
///</param>
/// <param name="type">
/// This parameter is the type of ODBC handle passed in
/// the next parameter.
///</param>
/// <param name="handle">
/// This parameter is the handle on which the error occurred.
///</param>
///<summary>
/// This method iterates though the error stack for the handle passed
/// into the constructor and displays those errors on the console.
///</summary>
void Print()
{
SQLSMALLINT i = 0, len = 0;
SQLINTEGER native;
SQLTCHAR state[9], text[256];
SQLRETURN sqlReturn = SQL_SUCCESS;
if ( m_handle == SQL_NULL_HANDLE )
{
wprintf_s(TEXT("The error handle is not a valid handle.\n"), m_iLine);
return;
}
sqlReturn = SQLGetDiagRec(
m_type,
m_handle,
++i,
state,
&native,
text,
sizeof(text)/sizeof(SQLTCHAR),
&len);
if ( SQL_SUCCEEDED(sqlReturn) )
wprintf_s(TEXT("Error(%d, %ld, %s) : %s\n"), i, native, state, text);
}
}
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 7 of 9
};
try
{
if ( (srcHandle = CreateFile(
srcFilePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL)) == INVALID_HANDLE_VALUE )
throw szErrMsgSrc;
if ( (dstHandle = OpenSqlFilestream(
dstFilePath,
Write,
0,
transactionToken,
cbTransactionToken,
0)) == INVALID_HANDLE_VALUE)
throw szErrMsgDst;
DWORD bytesRead = 0;
DWORD bytesWritten = 0;
do
{
if ( ReadFile(srcHandle, buffer, COPYBUFFERSIZE, &bytesRead, NULL) == 0 )
throw szErrMsgRead;
if (bytesRead > 0)
{
if ( WriteFile(dstHandle, buffer, bytesRead, &bytesWritten, NULL) == 0
)
throw szErrMsgWrite;
}
} while (bytesRead > 0);
bRetCode = TRUE;
}
catch( TCHAR *szErrMsg )
{
wprintf_s(szErrMsg);
bRetCode = FALSE;
}
if ( srcHandle != INVALID_HANDLE_VALUE )
CloseHandle(srcHandle);
if ( dstHandle != INVALID_HANDLE_VALUE )
CloseHandle(dstHandle);
return bRetCode;
}
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 8 of 9
void main()
{
TCHAR *sqlDBQuery =
TEXT("INSERT INTO Archive.dbo.Records(Id, SerialNumber, Chart)")
TEXT(" OUTPUT GET_FILESTREAM_TRANSACTION_CONTEXT(), inserted.Chart.PathName()")
TEXT("VALUES (newid (), 5, CONVERT(VARBINARY, '**Temp**'))");
SQLCHAR transactionToken[32];
try
{
//These statements Initialize ODBC for the client application and
//connect to the database.
//This code assumes that the dataset name "Sql Server FILESTREAM"
//has been previously created on the client computer system. An
//ODBC DSN is created with the ODBC Data Source item in
//the Windows Control Panel.
if ( SQLGetData(hstmt, 1,
SQL_C_BINARY,
transactionToken,
sizeof(transactionToken),
&cbTransactionToken) != SQL_SUCCESS )
throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);
TCHAR dstFilePath[1024];
SQLINTEGER cbDstFilePath;
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009
Managing FILESTREAM Data by Using Win32 Page 9 of 9
if ( SQLCloseCursor(hstmt) != SQL_SUCCESS )
throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);
if ( CopyFileToSQL(
TEXT("C:\\Users\\Data\\chart1.jpg"),
dstFilePath,
transactionToken,
cbTransactionToken) == TRUE )
mode = SQL_COMMIT;
if ( hstmt != SQL_NULL_HANDLE )
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if ( hdbc != SQL_NULL_HANDLE )
SQLDisconnect(hdbc);
if ( hdbc != SQL_NULL_HANDLE )
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
if ( henv != SQL_NULL_HANDLE )
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
See Also
Reference
OpenSqlFilestream API [ http://msdn.microsoft.com/en-us/library/bb933972.aspx ]
Concepts
Win32 and Transact-SQL Conflicts [ http://msdn.microsoft.com/en-us/library/cc645941.aspx ]
Using FILESTREAM Storage in Client Applications [ http://msdn.microsoft.com/en-
us/library/bb933877.aspx ]
FSCTL_SQL_FILESTREAM_FETCH_OLD_CONTENT [ http://msdn.microsoft.com/en-
us/library/cc627407.aspx ]
Other Resources
Designing and Implementing FILESTREAM Storage [ http://msdn.microsoft.com/en-
us/library/bb895234.aspx ]
Tags:
Community Content
http://msdn.microsoft.com/en-us/library/cc645940(printer).aspx 10/22/2009