用于将varbinary数据保存到磁盘的脚本

SFu*_*n28 33 sql sql-server sql-server-2005 varbinary

我有一些varbinary数据存储在MS Sql Server 2005的表中.是否有人使用SQL代码将查询作为输入(假设查询保证返回单列varbinary)并将字节输出到磁盘(一个文件)每行?)我确信之前已经问了一千次,但谷歌搜索提出的主要是.net解决方案.我想要一个SQL解决方案.

SFu*_*n28 38

BCP方法对我不起作用.它写入磁盘的字节无法反序列化回我存储的.net对象.这意味着磁盘上的字节不等于存储的字节数.也许BCP正在写一些标题.我不确定.

我发现下面的代码在这里在文章底部.它很棒!虽然它是用于存储的BMP图像,但它适用于任何varbinary.

DECLARE @SQLIMG VARCHAR(MAX),
    @IMG_PATH VARBINARY(MAX),
    @TIMESTAMP VARCHAR(MAX),
    @ObjectToken INT

DECLARE IMGPATH CURSOR FAST_FORWARD FOR 
        SELECT csl_CompanyLogo from mlm_CSCompanySettingsLocalizations

OPEN IMGPATH 

FETCH NEXT FROM IMGPATH INTO @IMG_PATH 

WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @TIMESTAMP = 'd:\' + replace(replace(replace(replace(convert(varchar,getdate(),121),'-',''),':',''),'.',''),' ','') + '.bmp'

        PRINT @TIMESTAMP
        PRINT @SQLIMG

        EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
        EXEC sp_OASetProperty @ObjectToken, 'Type', 1
        EXEC sp_OAMethod @ObjectToken, 'Open'
        EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @IMG_PATH
        EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @TIMESTAMP, 2
        EXEC sp_OAMethod @ObjectToken, 'Close'
        EXEC sp_OADestroy @ObjectToken

        FETCH NEXT FROM IMGPATH INTO @IMG_PATH 
    END 

CLOSE IMGPATH
DEALLOCATE IMGPATH
Run Code Online (Sandbox Code Playgroud)

  • 要运行此程序,可能需要启用OLE自动化过程https://msdn.microsoft.com/en-us/library/ms191188.aspx. (3认同)
  • 要启用 OLE 自动化过程,请使用: `sp_configure '显示高级选项', 1;` `GO` `RECONFIGURE;` `GO` `sp_configure 'Ole Automation procedures', 1;` `GO` `RECONFIGURE;` (3认同)

Dus*_*ine 13

您可以使用BCP,而不是T-SQL,但效果很好.

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.txt" -T
Run Code Online (Sandbox Code Playgroud)

  • 出现提示时,请使用以下选项: - 输入字段XXX [varbinary(max)]的文件存储类型:<BLANK> <ENTER> - 输入字段XXX [8]的前缀长度:0 <ENTER> - 输入字段长度XXX [0]:<BLANK> <ENTER> - 输入字段终止符[无]:<BLANK> <ENTER> - 是否要将此格式信息保存在文件中?[是/否] n <ENTER> (4认同)
  • 您需要指定一个prefix-length 为0,而不是默认的8,这样文件长度就不会作为前缀(header)写在文件数据之前。 (2认同)

Atr*_*ige 13

我将这个添加到JohnOpincar的答案中,以便其他想要使用LinqPad的人可以更快地获得有效的解决方案.

/*
This LinqPad script saves data stored in a VARBINARY field to the specified folder.
1. Connect to SQL server and select the correct database in the connection dropdown (top right)
2. Change the Language to C# Program
3. Change "Attachments" to the name of your table that holds the VARBINARY data
4. Change "AttachmentBuffer" to the name of the field that holds the data
5. Change "Id" to the unique identifier field name
6. Change "1090" to the identity of the record you want to save
7. Change the path to where you want to save the file. Make sure you choose the right extension.

Notes: Windows 10 may give you "Access Denied" error when trying to save directly to C:\. Rather save to a subfolder.
*/

void Main()
{
    var context = this;
    var query = 
        from ci in context.Attachments
        where ci.Id == 1090
        select ci.AttachmentBuffer
    ;
    byte[] result = query.Single().ToArray();
    File.WriteAllBytes(@"c:\DEV\dumpfile.xlsx", result);
    Console.WriteLine("Done");
}
Run Code Online (Sandbox Code Playgroud)


Sea*_*hu 6

我知道这是一篇过时的文章,但我弄清楚了以下原因为何不起作用以及如何解决:

BCP "SELECT FileContent FROM table WHERE ID = 1" queryout "C:\file.JPG" -T -N
Run Code Online (Sandbox Code Playgroud)

原因是bcp将前缀长度放在文件的最开始。它是4个字节还是8个字节,取决于FileContent列的数据类型(text,ntext,image:4 varchar(max),varbinary(max):8参见https://msdn.microsoft.com/zh-cn /library/ms190779.aspx

使用二进制编辑器(如Visual Studio中的二进制编辑器)删除前缀字节,一切运行完美。:-)


小智 6

使用 Powershell

function SQLExecuteScalar([string]$pServer, [string]$pDatabase, [string]$pQuery)
{
    # Connection
    $pSQLConnection = New-Object System.Data.SqlClient.SqlConnection
    $pSQLConnection.ConnectionString = "Data Source=$($pServer);Initial Catalog=$($pDatabase);Integrated Security=SSPI;Application Name=FileExtractor.Powershell"
    $pSQLConnection.Open()

    # Command
    [System.Data.SqlClient.SqlCommand]$cmd = New-Object System.Data.SqlClient.SqlCommand($pQuery, $pSQLConnection)

    # Execute and Get scalar value
    [byte[]]$return = $cmd.ExecuteScalar()
    
    # Close Connection
    $pSQLConnection.Close()

    # Result to pipe
    return $return
}

[string]$Server = "MyServer"
[string]$DataBase = "MyDb"
[string]$Query = "select BlobValue from dbo.MyTable"
[string]$FileName = "C:\Temp\BlobValue.bin"

SQLExecuteScalar -pServer $Server -pDatabase $DataBase -pQuery $Query | Set-Content $FileName -Encoding Byte
Run Code Online (Sandbox Code Playgroud)


Joh*_*car 5

如果你有 linqpad,这有效:

void Main()
{
    var context = this;
    var query = 
        from ci in context.Images
        where ci.ImageId == 10
        select ci.Image
    ;
    var result = query.Single ();
    var bytes = Convert.FromBase64String(result);
    File.WriteAllBytes(@"c:\image.bmp", bytes);
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,我使用它,是的,您的答案是正确的,但前提是您正确配置了连接,但是您的答案中缺少此信息,对于新的 LinqPad 用户来说,这看起来很神奇……这是我唯一要说的 (6认同)
  • 这有效...?真的,所以 `var context = this` 会自动搜索你的 sql server 实例,会登录,会找到正确的数据库,它有一个存在 Images 表的方案......从来不知道 LinqPad 这么聪明!! (3认同)