SQL Server FileStream - 如何获取文件路径

时间:2013-10-28 04:58:45

标签: sql sql-server database filestream sqlfilestream

我正在开发这个应用程序,我需要将大数据文件上传到我的SQL Server数据库,并且我一直在使用FileStream来更有效地执行此操作。

我知道这些文件直接存储在我系统的文件夹中(C:\ CryptoDB)。

问题是,我需要操纵这些文件(解密它们),但我无法恢复它们的文件路径。 这样做,我就可以直接操作它们,而不必通过SQL重新下载它们,这是一种真正的浪费。

到目前为止我能做到的事情:

我的表:

CREATE TABLE [arquivo] (
[idUsuario]   INT NOT NULL,
[fileState]   INT NOT NULL,
[fileContent] varbinary(max) FILESTREAM,
[fileName]    VARCHAR (150)   NULL,
[fileSize]    VARCHAR (50)    NULL,

id UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE,

CONSTRAINT [FK_arquivo_usuario] FOREIGN KEY ([idUsuario]) REFERENCES usuario(id)
);

插入:

Insert into arquivo(id, idUsuario, fileState, fileContent, fileName, fileSize) Values(
newId(),
1,
5,
(SELECT * FROM OPENROWSET(BULK 'c:\medio.jpeg', SINGLE_BLOB) AS varbinary(max)) ,
'medio.jpeg',
'123'
)

当我尝试恢复文件路径时:

DECLARE @filePath varchar(max)

SELECT @filePath = fileContent.PathName()
FROM arquivo

PRINT @filepath

我得到的结果:

\\TEHORT-PC\MSSQLSERVER\v02-A60EC2F8-2B24-11DF-9CC3-AF2E56D89593\CryptoDB\dbo\arquivo\fileContent\31E3697E-0576-4B0F-B0AA-6E046F4116A1\VolumeHint-HarddiskVolume2

文件实际上是:

C:\CryptoDB\DATA\902a7d8d-c8c1-43b0-8c94-b12319293f42\7febdbd1-02c6-4b00-aa3c-a72bee80ef9c\

3 个答案:

答案 0 :(得分:1)

  1. 获取所有FILESTREAM数据的物理位置的SQL查询(source

    SELECT t.name AS'table',             c.name AS'列',             fg.name AS'filegroup_name',             dbf.type_desc AS'type_description',             dbf.physical_name AS'physical_location' FROM sys.filegroups fg INNER JOIN sys.database_files dbf ON fg.data_space_id = dbf.data_space_id INNER JOIN sys.tables t ON fg.data_space_id = t.filestream_data_space_id INNER JOIN sys.columns c ON t.object_id = c.object_id AND c.is_filestream = 1

  2. All FILESTREAM BLOB-fields query result sample

    1. 用于获取服务器上FILESTREAM数据的子文件夹的SQL查询: (这些表仅在专用管理员连接(DAC)中使用)。

      SELECT o.name AS [Table],cp.name AS [Column],r.rsguid AS [Rowset GUID],rs.colguid AS [Column GUID] FROM SYS.SYSROWSETS r CROSS APPLY sys.sysrscols rs JOIN sys.partitions p ON rs.rsid = p.partition_id JOIN sys.objects o ON o.object_id = p.object_id JOIN sys.syscolpars cp ON cp.colid = rs.rscolid WHERE rs.colguid IS NOT NULL和o.object_id = cp.id AND r.rsguid IS NOT NULL AND r.rowsetid = rs.rsid AND o.name ='DOCUMENT'和cp.name ='DIGITAL_FILE';

    2. 2.1。查询结果:

        

      表:文件
        列: DIGITAL_FILE
        行集GUID: 0x6AA5E6045794D34D8B1FAC0F49A49B0A
        列GUID: 0xD756E638FB2CC843AE98F489B57F6D7D

      从这个guid计算子路径:

        

      0x6AA5E6045794D34D8B1FAC0F49A49B0A等于此路径:   04e6a56a-9457-4dd3-8b1f-ac0f49a49b0a

           

      [逆转6AA5E604] - [逆转5794] - [逆转D34D] - [逆转8B1F] - [原始AC0F49A49B0A]

           

      0xD756E638FB2CC843AE98F489B57F6D7D等于此路径:   38e656d7-2cfb-43c8-ae98-f489b57f6d7d(previus guid解析中的规则)

      2.2结果计算FILESTREAM存储的完整路径:

        

      i:\ SQL Base posc_astrachan FileStreams \ GTMK \ GTM_FILE_STREAM \ 04e6a56a-9457-4dd3-8b1f-ac0f49a49b0a \ 38e656d7-2cfb-43c8-ae98-f489b57f6d7d

      1. 获取NTFS文件夹中BLOB值的原始文件名。
      2. 3.1。查询高级SQL Server页面信息的存储过程

        SET ANSI_NULLS ON
        SET QUOTED_IDENTIFIER ON
        GO
        
        CREATE PROCEDURE [dbo].[procDBCC_PAGE]
            @db_name varchar (500),
            @filenum INT,
            @pagenum INT
        AS
        BEGIN
        SET NOCOUNT ON 
        DBCC TRACEON (3604);
        DBCC PAGE (@db_name, @filenum, @pagenum, 3) WITH TABLERESULTS;
        SET NOCOUNT OFF     
        END
        

        3.2。用于查询表

        的FILESTREAM的BLOB字段的原始文件名的存储过程
        SET ANSI_NULLS ON
        SET QUOTED_IDENTIFIER ON
        GO
        
        CREATE  PROCEDURE [dbo].[procFindLogSequenceNumber] 
        -- @TableName varchar (500),
         @instanceS varchar (19), -- key value for filed INSTANCE_S
         @tableName varchar(500), -- DOCUMENT
         @keyFieldName varchar(500), -- INSTANCE_S
         @LogSequenceNumber varchar (500) OUTPUT
        AS
        SET NOCOUNT ON
        
        DECLARE @db_name varchar (500) 
        DECLARE @filenum INT
        DECLARE @pagenum INT
        DECLARE @slotnum INT
        DECLARE @rid varchar (100) 
        DECLARE @ridDotted varchar (100) 
        
        DECLARE @parent_object varchar (500)
        
        DECLARE @sql nvarchar(2000)
        DECLARE @sqlTable Table(physloc varchar(100))
        
        DECLARE @DBCC_PAGE_Output Table ([ParentObject] varchar (MAX), [Object] varchar (MAX), [Field] varchar (MAX), [VALUE] varchar (MAX))
        
        SET @db_name = db_name()
        
        SET @sql = 'SELECT top 1 sys.fn_PhysLocFormatter (%%physloc%%) AS [PhysicalRID] FROM '+@tableName+' WHERE '
                     +@keyFieldName+' = '''+@instanceS+''''
        
        INSERT @sqlTable (physloc)
        EXECUTE sp_executesql @sql
        
        SET @rid = (select top 1 physloc from @sqlTable)
        if @rid is NULL
        BEGIN
          RETURN -1;
        END
        
        -- parse (@rid): (1:1172779:6)  1-@filenum, 2- @pagenum, 3- @slotnum 
        SET @ridDotted = Replace(@rid, ':', '.');
        SET @ridDotted = Replace(@ridDotted, '(', '');
        SET @ridDotted = Replace(@ridDotted, ')', '');
        
        SET @filenum = (SELECT Parsename(@ridDotted, 3))
        SET @pagenum = (SELECT Parsename(@ridDotted, 2))
        SET @slotnum = (SELECT Parsename(@ridDotted, 1))
        
        INSERT @DBCC_PAGE_Output ([ParentObject], [Object], [Field], [VALUE]) 
        EXECUTE procDBCC_PAGE @db_name, @filenum , @pagenum
        
        SET @parent_object = (SELECT TOP 1 [ParentObject] FROM @DBCC_PAGE_Output WHERE [Field] = 'INSTANCE_S'
         AND [VALUE] = @instanceS) 
        
        --CreateLSN field Only
        SET @LogSequenceNumber = (SELECT [VALUE] FROM  @DBCC_PAGE_Output WHERE 
         [ParentObject] = @parent_object AND
         [Field] = 'CreateLSN'
        )
        
        if @LogSequenceNumber is NULL
        BEGIN
          RETURN -1;
        END
        
        -- result 0006c050:00000120:0090 (442448:288:144)
        -- clear (...)
        SET @LogSequenceNumber = Replace(@LogSequenceNumber, ' ', '.');
        SET @LogSequenceNumber = (SELECT Parsename(@LogSequenceNumber, 2))
        
        --replace ":" to "-"
        SET @LogSequenceNumber = Replace(@LogSequenceNumber, ':', '-');
        
        SET NOCOUNT OFF
        

        3.3。对于BLOB的NTFS文件夹中获取文件名的存储过程的示例查询:

        declare @filestreamFileName varchar(500);
        exec procFindLogSequenceNumber 'ZW_NU9hGZ0CKoSXYAoc', 'DOCUMENT', 'INSTANCE_S', @filestreamFileName OUTPUT
        select @filestreamFileName
        

        3.4。结果(NTFS文件夹中的原始文件名):

          

        0003137a-00001244-00d0

        3.5。结果完整路径:

          

        i:\ SQL Base posc_astrachan FileStreams \ GTMK \ GTM_FILE_STREAM \ 04e6a56a-9457-4dd3-8b1f-ac0f49a49b0a \ 38e656d7-2cfb-43c8-ae98-f489b57f6d7d \ 0003137a-00001244-00d0

答案 1 :(得分:0)

您获得的路径是正确的,您应该获取网络共享路径而不是本地路径并使用SqlFileStream打开流。

https://msdn.microsoft.com/en-us/library/system.data.sqltypes.sqlfilestream%28v=vs.110%29.aspx

您还可以使用OpenSqlFilestream方法获取文件句柄,即在Windows API中使用它。

https://msdn.microsoft.com/en-us/library/bb933972.aspx

答案 2 :(得分:0)

亚历山大的答案很棒,为我节省了很多麻烦,将页面/插槽号码与实际的 LSN 相关联。在我使用SQL Server 2008 R2的情况下,我不得不对他的SP进行一些调整以使其正常工作,那些是:

SPs第一个参数:

  

@instanceS varchar (100), - 提交的INSTANCE_S的关键值

在我的情况下,这是一个uniqueidentifier,所以我需要一个更大的varchar,原始值是19。

查询DBCC PAGE输出时:

  

SET @parent_object =(SELECT TOP 1 [ParentObject] FROM   @DBCC_PAGE_Output WHERE [Field] = @keyFieldName AND [VALUE] =   @instanceS)

它最初声明"[Field] = 'INSTANCE_S'"显然硬编码了一个适用于OP但不适合我的值。它需要匹配FILESTREAM表的关键字段的名称。

还要澄清 SP输入参数

  

@instanceS =标识行的实际列值。将   这总是与列集匹配为表" RowGuid"?
  @tableName =很清楚。 FILESTREAM表的名称。
  @keyFieldName =表格的键列名称。应该是   来自@instanceS的源列。