Criar aplicativos clientes para dados FILESTREAMCreate Client Applications for FILESTREAM Data

APLICA-SE A: simSQL Server nãoBanco de Dados SQL do Azure nãoSQL Data Warehouse do Azure nãoParallel Data Warehouse APPLIES TO: yesSQL Server noAzure SQL Database noAzure SQL Data Warehouse noParallel Data Warehouse

Você pode usar as APIs do Win32 para ler e gravar dados em um FILESTREAM BLOB.You can use Win32 APIs to read and write data to a FILESTREAM BLOB. As seguintes etapas são exigidas:The following steps are required:

  • Leia o caminho do arquivo de FILESTREAM.Read the FILESTREAM file path.

  • Leia o contexto de transação atual.Read the current transaction context.

  • Obtenha um identificador de Win32 e use-o para ler e gravar dados no FILESTREAM BLOB.Obtain a Win32 handle and use the handle to read and write data to the FILESTREAM BLOB.

Observação

Os exemplos citados neste tópico exigem o banco de dados e a tabela habilitados para FILESTREAM criados em Criar um banco de dados habilitado para FILESTREAM e Criar uma tabela para armazenar dados de FILESTREAM.The examples in this topic require the FILESTREAM-enabled database and table that are created in Create a FILESTREAM-Enabled Database and Create a Table for Storing FILESTREAM Data.

Funções para trabalhar com dados FILESTREAMFunctions for Working with FILESTREAM Data

Quando FILESTREAM é usado para armazenar dados BLOB (objeto binário grande), é possível usar APIs do Win32 para trabalhar com os arquivos.When you use FILESTREAM to store binary large object (BLOB) data, you can use Win32 APIs to work with the files. Para oferecer suporte ao trabalho com dados BLOB do FILESTREAM em aplicativos Win32, o SQL ServerSQL Server fornece as seguintes funções e API:To support working with FILESTREAM BLOB data in Win32 applications, SQL ServerSQL Server provides the following functions and API:

  • PathName retorna um caminho como um token para um BLOB.PathName returns a path as a token to a BLOB. Um aplicativo usa esse token para obter um identificador do Win32 e operar em dados BLOB.An application uses this token to obtain a Win32 handle and operate on BLOB data.

    Quando o banco de dados que contém dados FILESTREAM pertence a um grupo de disponibilidade AlwaysOn, a função PathName retorna um VNN (nome de rede virtual) em vez de um nome do computador.When the database that contains FILESTREAM data belongs to an Always On availability group, then the PathName function returns a virtual network name (VNN) instead of a computer name.

  • GET_FILESTREAM_TRANSACTION_CONTEXT() retorna um token que representa a transação atual de uma sessão.GET_FILESTREAM_TRANSACTION_CONTEXT() returns a token that represents the current transaction of a session. Um aplicativo usa esse token para associar operações de fluxo contínuo do sistema de arquivos do FILESTREAM à transação.An application uses this token to bind FILESTREAM file system streaming operations to the transaction.

  • A API OpenSqlFilestream obtém um identificador de arquivo Win32.The OpenSqlFilestream API obtains a Win32 file handle. O aplicativo usa o identificador para transmitir os dados de FILESTREAM e, em seguida, pode passar o identificador para as seguintes APIs do Win32: ReadFile, WriteFile, TransmitFile, SetFilePointer, SetEndOfFile ou FlushFileBuffers.The application uses the handle to stream the FILESTREAM data, and can then pass the handle to the following Win32 APIs: ReadFile, WriteFile, TransmitFile, SetFilePointer, SetEndOfFile, or FlushFileBuffers. Se o aplicativo chamar qualquer outra API usando o identificador, um erro ERROR_ACCESS_DENIED será retornado.If the application calls any other API by using the handle, an ERROR_ACCESS_DENIED error is returned. O aplicativo deve fechar o identificador usando CloseHandle.The application should close the handle by using CloseHandle.

O acesso ao contêiner de dados All FILESTREAM é executado em uma transação SQL ServerSQL Server .All FILESTREAM data container access is performed in a SQL ServerSQL Server transaction. Transact-SQLTransact-SQL podem ser executadas na mesma transação para manter a consistência entre dados SQL e dados FILESTREAM.statements can be executed in the same transaction to maintain consistency between SQL data and FILESTREAM data.

Etapas para acessar dados FILESTREAMSteps for Accessing FILESTREAM Data

Lendo o caminho do arquivo de FILESTREAMReading the FILESTREAM File Path

Cada célula em uma tabela de FILESTREAM tem um caminho de arquivo associado.Each cell in a FILESTREAM table has a file path that is associated with it. Para ler o caminho, use a propriedade PathName de uma coluna varbinary(max) em uma instrução Transact-SQLTransact-SQL .To read the path, use the PathName property of a varbinary(max) column in a Transact-SQLTransact-SQL statement. Os exemplos a seguir mostram como ler o caminho de arquivo de uma coluna varbinary(max) .The following example shows how to read the file path of a varbinary(max) column.

DECLARE @filePath varchar(max)

SELECT @filePath = Chart.PathName()
FROM Archive.dbo.Records
WHERE SerialNumber = 3

PRINT @filepath

Lendo o contexto da transaçãoReading the Transaction Context

Para obter o contexto da transação atual, use a função Transact-SQLTransact-SQL GET_FILESTREAM_TRANSACTION_CONTEXT() .To obtain the current transaction context, use the Transact-SQLTransact-SQL GET_FILESTREAM_TRANSACTION_CONTEXT() function. O exemplo seguinte mostra como começar uma transação e ler o contexto de transação atual.The following example shows how to begin a transaction and read the current transaction context.

DECLARE @txContext varbinary(max)

BEGIN TRANSACTION
SELECT @txContext = GET_FILESTREAM_TRANSACTION_CONTEXT()
PRINT @txContext
COMMIT

Obtendo um identificador de arquivo Win32Obtaining a Win32 File Handle

Para obter um identificador de arquivo do Win32, chame a API OpenSqlFilestream.To obtain a Win32 file handle, call the OpenSqlFilestream API. Esta API é exportada do arquivo sqlncli.dll.This API is exported from the sqlncli.dll file. O identificador retornado pode ser passado para qualquer uma das seguintes APIs do Win32: ReadFile, WriteFile, TransmitFile, SetFilePointer, SetEndOfFile ou FlushFileBuffers.The returned handle can be passed to any of the following Win32 APIs: ReadFile, WriteFile, TransmitFile, SetFilePointer, SetEndOfFile, or FlushFileBuffers. Os exemplos a seguir mostram como obter um identificador de arquivo Win32 e usá-lo para ler e gravar dados no FILESTREAM BLOB.The following 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)");

            SqlCommand sqlCommand = new SqlCommand();
            sqlCommand.Connection = sqlConnection;

            try
            {
                sqlConnection.Open();

                //The first task is to retrieve the file path
                //of the SQL FILESTREAM BLOB that we want to
                //access in the application.

                sqlCommand.CommandText =
                      "SELECT Chart.PathName()"
                    + " FROM Archive.dbo.Records"
                    + " WHERE SerialNumber = 3";

                String filePath = null;

                Object pathObj = sqlCommand.ExecuteScalar();
                if (DBNull.Value != pathObj)
                    filePath = (string)pathObj;
                else
                {
                    throw new System.Exception(
                        "Chart.PathName() failed"
                      + " to read the path name "
                      + " for the Chart column.");
                }

                //The next task is to obtain a transaction
                //context. All FILESTREAM BLOB operations
                //occur within a transaction context to
                //maintain data consistency.

                //All SQL FILESTREAM BLOB access must occur in 
                //a transaction. MARS-enabled connections
                //have specific rules for batch scoped transactions,
                //which the Transact-SQL BEGIN TRANSACTION statement
                //violates. To avoid this issue, client applications 
                //should use appropriate API facilities for transaction management, 
                //management, such as the SqlTransaction class.

                SqlTransaction transaction = sqlConnection.BeginTransaction("mainTranaction");
                sqlCommand.Transaction = transaction;

                sqlCommand.CommandText =
                    "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()";

                Object obj = sqlCommand.ExecuteScalar();
                byte[] txContext = (byte[])obj;

                //The next step is to obtain a handle that
                //can be passed to the Win32 FILE APIs.

                SqlFileStream sqlFileStream = new SqlFileStream(filePath, txContext, FileAccess.ReadWrite);

                byte[] buffer = new byte[512];

                int numBytes = 0;

                //Write the string, "EKG data." to the FILESTREAM BLOB.
                //In your application this string would be replaced with
                //the binary data that you want to write.

                string someData = "EKG data.";
                Encoding unicode = Encoding.GetEncoding(0);

                sqlFileStream.Write(unicode.GetBytes(someData.ToCharArray()),
                    0,
                    someData.Length);

                //Read the data from the FILESTREAM
                //BLOB.

                sqlFileStream.Seek(0L, SeekOrigin.Begin);

                numBytes = sqlFileStream.Read(buffer, 0, buffer.Length);

                string readData = unicode.GetString(buffer);

                if (numBytes != 0)
                    Console.WriteLine(readData);

                //Because reading and writing are finished, FILESTREAM 
                //must be closed. This closes the c# FileStream class, 
                //but does not necessarily close the underlying 
                //FILESTREAM handle. 
                sqlFileStream.Close();

                //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 
Imports System.Data.SqlTypes 

Module Module1
    Public Sub Main(ByVal args As String())
        '        Dim sqlConnection As New SqlConnection("Integrated Security=true;server=(local)")
        Dim sqlConnection As New SqlConnection("Integrated Security=true;server=kellyreyue\MSSQL1")

        Dim sqlCommand As New SqlCommand()
        sqlCommand.Connection = sqlConnection

        Try
            sqlConnection.Open()

            'The first task is to retrieve the file path 
            'of the SQL FILESTREAM BLOB that we want to 
            'access in the application. 

            sqlCommand.CommandText = "SELECT Chart.PathName()" + " FROM Archive.dbo.Records" + " WHERE SerialNumber = 3"

            Dim filePath As String = Nothing

            Dim pathObj As Object = sqlCommand.ExecuteScalar()
            If Not pathObj.Equals(DBNull.Value) Then
                filePath = DirectCast(pathObj, String)
            Else
                Throw New System.Exception("Chart.PathName() failed" + " to read the path name " + " for the Chart column.")
            End If

            'The next task is to obtain a transaction 
            'context. All FILESTREAM BLOB operations 
            'occur within a transaction context to 
            'maintain data consistency. 

            'All SQL FILESTREAM BLOB access must occur in 
            'a transaction. MARS-enabled connections 
            'have specific rules for batch scoped transactions, 
            'which the Transact-SQL BEGIN TRANSACTION statement 
            'violates. To avoid this issue, client applications 
            'should use appropriate API facilities for transaction management, 
            'management, such as the SqlTransaction class. 

            Dim transaction As SqlTransaction = sqlConnection.BeginTransaction("mainTranaction")
            sqlCommand.Transaction = transaction

            sqlCommand.CommandText = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()"

            Dim obj As Object = sqlCommand.ExecuteScalar()
            Dim txContext As Byte() = Nothing

            Dim contextLength As UInteger

            If Not obj.Equals(DBNull.Value) Then
                txContext = DirectCast(obj, Byte())
                contextLength = txContext.Length()
            Else
                Dim message As String = "GET_FILESTREAM_TRANSACTION_CONTEXT() failed"
                Throw New System.Exception(message)
            End If

            'The next step is to obtain a handle that 
            'can be passed to the Win32 FILE APIs. 

            Dim sqlFileStream As New SqlFileStream(filePath, txContext, FileAccess.ReadWrite)

            Dim buffer As Byte() = New Byte(511) {}

            Dim numBytes As Integer = 0

            'Write the string, "EKG data." to the FILESTREAM BLOB. 
            'In your application this string would be replaced with 
            'the binary data that you want to write. 

            Dim someData As String = "EKG data."
            Dim unicode As Encoding = Encoding.GetEncoding(0)

            sqlFileStream.Write(unicode.GetBytes(someData.ToCharArray()), 0, someData.Length)

            'Read the data from the FILESTREAM 
            'BLOB. 

            sqlFileStream.Seek(0, SeekOrigin.Begin)

            numBytes = sqlFileStream.Read(buffer, 0, buffer.Length)

            Dim readData As String = unicode.GetString(buffer)

            If numBytes <> 0 Then
                Console.WriteLine(readData)
            End If

            'Because reading and writing are finished, FILESTREAM 
            'must be closed. This closes the c# FileStream class, 
            'but does not necessarily close the underlying 
            'FILESTREAM handle. 
            sqlFileStream.Close()

            '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>

#define COPYBUFFERSIZE 4096

/// <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:
    /// <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>

    ODBCErrors(int iLine, SQLSMALLINT type, SQLHANDLE handle)
    {
        m_iLine  = iLine;
        m_type   = type;
        m_handle = handle;
    }

    ///<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;
        }

        wprintf_s(TEXT("Error Line(%d)\n"), m_iLine);

        while( sqlReturn == SQL_SUCCESS )
        {
            len = 0;

            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);
        }
    }
};


BOOL CopyFileToSQL(LPTSTR srcFilePath, LPTSTR dstFilePath, LPBYTE transactionToken, SQLINTEGER cbTransactionToken)
{
    BOOL bRetCode = FALSE;

    HANDLE srcHandle = INVALID_HANDLE_VALUE;
    HANDLE dstHandle = INVALID_HANDLE_VALUE;
    BYTE   buffer[COPYBUFFERSIZE] = { 0 };

    TCHAR *szErrMsgSrc   = TEXT("Error opening source file.");
    TCHAR *szErrMsgDst   = TEXT("Error opening destFile file.");
    TCHAR *szErrMsgRead  = TEXT("Error reading source file.");
    TCHAR *szErrMsgWrite = TEXT("Error writing SQL file.");

    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;
}

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];
    
    SQLHANDLE henv = SQL_NULL_HANDLE;
    SQLHANDLE hdbc              = SQL_NULL_HANDLE;
    SQLHANDLE hstmt             = SQL_NULL_HANDLE;

    try
    {
        //These statements Initialize ODBC for the client application and
        //connect to the database.

        if ( SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_ENV, henv);

        if ( SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,(void*)SQL_OV_ODBC3, NULL) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_ENV, henv);

        if ( SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_ENV, henv);

        //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 ( SQLConnect(hdbc, TEXT("Sql Server FILESTREAM"),
                SQL_NTS, NULL, 0, NULL, 0) <= 0 )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_DBC, hdbc);

        //FILESTREAM requires that all read and write operations occur
        //within a transaction.
        if ( SQLSetConnectAttr(hdbc,
            SQL_ATTR_AUTOCOMMIT,
            (SQLPOINTER)SQL_AUTOCOMMIT_OFF,
            SQL_IS_UINTEGER) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_DBC, hdbc);

        if ( SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_DBC, hdbc);

        if ( SQLExecDirect(hstmt, sqlDBQuery, SQL_NTS) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);

        //Retrieve the transaction token.
        if ( SQLFetch(hstmt) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);

        SQLINTEGER cbTransactionToken = sizeof(transactionToken);

        if ( SQLGetData(hstmt, 1,
            SQL_C_BINARY,
            transactionToken,
            sizeof(transactionToken),
            &cbTransactionToken) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);

        //Retrieve the file path for the inserted record.

        TCHAR dstFilePath[1024];
        SQLINTEGER cbDstFilePath;

        if ( SQLGetData(hstmt, 2, SQL_C_TCHAR, dstFilePath, sizeof(dstFilePath), &cbDstFilePath) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);

        if ( SQLCloseCursor(hstmt) != SQL_SUCCESS )
            throw new ODBCErrors(__LINE__, SQL_HANDLE_STMT, hstmt);

        SQLUSMALLINT mode = SQL_ROLLBACK;

        if ( CopyFileToSQL(
            TEXT("C:\\Users\\Data\\chart1.jpg"),
            dstFilePath,
            transactionToken,
            cbTransactionToken) == TRUE )
            mode = SQL_COMMIT;

        SQLTransact(henv, hdbc, mode);
    }
    catch(ODBCErrors *pErrors)
    {
        pErrors->Print();
        delete pErrors;
    }

    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);
}

Práticas recomendadas para design e implementação de aplicativosBest Practices for Application Design and Implementation

  • Ao criar e implementar aplicativos que usam FILESTREAM, considere as seguintes diretrizes:When you are designing and implementing applications that use FILESTREAM, consider the following guidelines:

  • Use NULL em vez de 0x representar uma coluna de FILESTREAM não inicializada.Use NULL instead of 0x to represent a non-initialized FILESTREAM column. O valor 0x faz com que um arquivo seja criado; NULL não faz.The 0x value causes a file to be created, and NULL does not.

  • Evite operações de inserção e de exclusão em tabelas que contêm colunas de FILESTREAM não nulas.Avoid insert and delete operations in tables that contain nonnull FILESTREAM columns. As operações de inserção e de exclusão podem modificar as tabelas de FILESTREAM que são usadas para coleta de lixo.Insert and delete operations can modify the FILESTREAM tables that are used for garbage collection. Isso pode fazer com que o desempenho de um aplicativo seja reduzido ao longo do tempo.This can cause an application's performance to decrease over time.

  • Em aplicativos que usam replicação, use NEWSEQUENTIALID() em vez de NEWID().In applications that use replication, use NEWSEQUENTIALID() instead of NEWID(). NEWSEQUENTIALID() executa melhor que NEWID() para geração de GUID nesses aplicativos.NEWSEQUENTIALID() performs better than NEWID() for GUID generation in these applications.

  • A API FILESTREAM foi projetada para acesso de streaming do Win32 aos dados.The FILESTREAM API is designed for Win32 streaming access to data. Evite usar Transact-SQLTransact-SQL para ler ou gravar BLOBs (objetos binários grandes) de FILESTREAM maiores que 2 MB.Avoid using Transact-SQLTransact-SQL to read or write FILESTREAM binary large objects (BLOBs) that are larger than 2 MB. Se você precisar ler ou gravar dados BLOB de Transact-SQLTransact-SQL, verifique se todos os dados BLOB serão consumidos antes de você tentar abrir o BLOB de FILESTREAM no Win32.If you must read or write BLOB data from Transact-SQLTransact-SQL, make sure that all BLOB data is consumed before you try to open the FILESTREAM BLOB from Win32. O não consumo de todos os dados Transact-SQLTransact-SQL pode provocar falha em quaisquer operações sucessivas de abertura ou de fechamento de FILESTREAM.Failure to consume all the Transact-SQLTransact-SQL data might cause any successive FILESTREAM open or close operations to fail.

  • Evite instruções Transact-SQLTransact-SQL que atualizam, acrescentam ou precedem dados no BLOB de FILESTREAM.Avoid Transact-SQLTransact-SQL statements that update, append or prepend data to the FILESTREAM BLOB. Isso faz com que os dados BLOB sejam colocados no spool no banco de dados tempdb e retornados em um novo arquivo físico.This causes the BLOB data to be spooled into the tempdb database and then back into a new physical file.

  • Evite acrescentar atualizações de BLOBs pequenos a um BLOB de FILESTREAM.Avoid appending small BLOB updates to a FILESTREAM BLOB. Cada acréscimo faz com que os arquivos FILESTREAM subjacentes sejam copiados.Each append causes the underlying FILESTREAM files to be copied. Se um aplicativo precisar acrescentar BLOBs pequenos, grave os BLOBs em uma coluna varbinary(max) e execute uma única operação de gravação no BLOB de FILESTREAM quando o número de BLOBs atingir um limite predeterminado.If an application has to append small BLOBs, write the BLOBs into a varbinary(max) column, and then perform a single write operation to the FILESTREAM BLOB when the number of BLOBs reaches a predetermined limit.

  • Evite recuperar o comprimento de dados de muitos arquivos de BLOB em um aplicativo.Avoid retrieving the data length of lots of BLOB files in an application. Essa é uma operação demorada porque o tamanho não é armazenado no Mecanismo de Banco de Dados do SQL ServerSQL Server Database Engine.This is a time-consuming operation because the size is not stored in the Mecanismo de Banco de Dados do SQL ServerSQL Server Database Engine. Se você precisar determinar o tamanho de um arquivo de BLOB, use a função DATALENGTH() do Transact-SQLTransact-SQL para determinar o tamanho do BLOB se ele estiver fechado.If you must determine the length of a BLOB file, use the Transact-SQLTransact-SQL DATALENGTH() function to determine the size of the BLOB if it is closed. A função DATALENGTH() não abre o arquivo de BLOB para determinar seu tamanho.DATALENGTH() does not open the BLOB file to determine its size.

  • Se um aplicativo usar o protocolo SMB1, os dados BLOB de FILESTREAM deverão ser lidos em múltiplos de 60 KB para otimizar o desempenho.If an application uses Message Block1 (SMB1) protocol, FILESTREAM BLOB data should be read in 60-KB multiples to optimize performance.

Consulte TambémSee Also

Evitar conflitos com operações de banco de dados em aplicativos de FILESTREAM Avoid Conflicts with Database Operations in FILESTREAM Applications
Acessar dados do FILESTREAM com OpenSqlFilestream Access FILESTREAM Data with OpenSqlFilestream
Objeto binário grande (Blob) Dados (SQL Server) Binary Large Object (Blob) Data (SQL Server)
Fazer atualizações parciais em dados do FILESTREAMMake Partial Updates to FILESTREAM Data