SQL Server 导出 Blob 损坏所有文件

Posted

技术标签:

【中文标题】SQL Server 导出 Blob 损坏所有文件【英文标题】:SQL Server Export Blob Corrupts All Files 【发布时间】:2019-11-03 07:05:01 【问题描述】:

我正在使用此代码导出 blob:

sp_configure 'Ole Automation Procedures', 1;  
GO  
RECONFIGURE;  
GO

DECLARE @outout_path varchar(50) = 'D:\blob',
        @i bigint,
        @init int,
        @data varbinary(max),
        @file_path varchar(max),
        @folder_path  varchar(max)

DECLARE @Doctable TABLE (id int identity(1,1) , [FileName]  varchar(100), file_data varBinary(max) )

INSERT INTO @Doctable([FileName],file_data)
Select top 10 thefilename, file_data FROM  schm.table_with_blobs

SELECT @i = COUNT(1) FROM @Doctable

WHILE @i >= 1
BEGIN

    SELECT @data = [file_data],
           @file_path = @outout_path + '\'+ cast(id as varchar) + '\' + [FileName],
           @folder_path = @outout_path + '\'+ cast(id as varchar)
    FROM @Doctable
    WHERE id = @i

  EXEC [dbo].[CreateFolder]  @folder_path

  EXEC sp_OACreate 'ADODB.Stream', @init OUTPUT;
  EXEC sp_OASetProperty @init, 'Type', 1; 
  EXEC sp_OAMethod @init, 'Open';
  EXEC sp_OAMethod @init, 'Write', NULL, @data;
  EXEC sp_OAMethod @init, 'SaveToFile', NULL, @file_path, 2;
  EXEC sp_OAMethod @init, 'Close';
  EXEC sp_OADestroy @init;

  print 'Document Generated at - '+  @file_path  

SELECT @data = NULL,
       @init = NULL,
       @file_path = NULL,
       @folder_path = NULL;

SET @i -= 1;
END

所有文件都按预期以正确的文件格式导出。但是,无论文件格式如何,所有文件都已损坏且无法打开。我可以调整什么来避免这种情况?我是否需要更明确地标注文件类型(在thefilename 字段中可用)?

【问题讨论】:

尝试验证schm_table_with_blobs 是否确实包含您期望的数据,方法是对应该包含或多或少可读数据的文件类型执行CONVERT(VARCHAR(MAX), file_data).txt 是理想的,但是.pdf 可以在紧要关头做)。此外,使用文本或十六进制编辑器打开导出的文件,查看是否与数据库中的内容匹配。如果问题出在ADODB.Stream 的使用或数据本身,这样您就可以缩小范围。 @JeroenMostert .txt 在数据库中看起来正常并正确导出(即未损坏)。其他文件类型(例如 PDF、Excel)在数据库中是乱码……在记事本中打开导出的文件时也是一样的乱码。 不确定这是否意味着 ADODB 流是问题 【参考方案1】:

我遇到了类似的问题,但我使用 BCP 导出而不是使用 ADODB。 我必须做两件事:

将 varbinary 转换为 varchar 或 nvarchar 将 BCP 导出为 原始

这是我想出的 BCP 解决方案:

Declare @patient int, @mincount int, @maxcount int,@filename varchar(200), @script varchar(2000),@fileid varchar(10)

Set @patient=2;
set @mincount=1;

Declare @mydocs as table
(filename varchar(255), filebody image, drank int, file_id int)
insert into @mydocs
Select taf.Attachment_File_Name, taf.Attachment_File_Body, DENSE_RANK() OVER (ORDER BY taf.attachment_file_id) as drank, taf.Attachment_File_ID FROM [CNGSTT].[dbo].[tblAttachment] ta 
left join  [CNGSTT].[dbo].[tblAttachmentFile] taf 
on taf.Attachment_ID=ta.Attachment_ID where ta.Patient_ID=@patient

Set @maxcount=(select MAX(drank) from @mydocs)

WHILE @mincount<=@maxcount
BEGIN

Set @filename = (select fle.FileName from @mydocs fle where drank=@mincount)
Set @fileid =(select fle.File_id from @mydocs fle where drank=@mincount)

set @script = 'bcp "SELECT cast(cast(Attachment_File_Body as varbinary(max)) as varchar(max)) from [tblattachmentfile] fle where Attachment_File_ID='+@fileid+'" queryout D:\temp\' + @filename + ' -T -c -C RAW'

exec master..xp_cmdshell @script
Set @mincount=@mincount+1
END

【讨论】:

谢谢 - 我会看看 BCP 路线。 BCP 与 ADODB 之间的优缺点是什么? 大多数情况下,除非您在外部运行它,否则您必须通过 xp_cmdshell 执行。可能值得尝试 ADODB 方法并尝试将 varbinary 作为 varchar 推入...快乐的实验! 是的,我尝试将其强制为 varchar/nvarchar,但没有运气 - 仍然损坏。不过谢谢! 在这种情况下,我的猜测是 ADODB 正在更改原始数据的代码页。在找到阻止 BCP 这样做的最佳方法之前,我必须进行大量的试验和错误。可能值得将文档放入数据库并再次退出,然后使用 Notepad++ 或类似工具将原始版本与数据库中的版本进行比较。让您对正在发生的事情有一个很好的了解。这似乎表明默认情况下 ADO 将导出为 Unicode docs.microsoft.com/en-us/sql/ado/reference/ado-api/… 我尝试使用EXEC sp_OASetProperty @init, 'Charset','Windows-1252' 设置字符集,但问题仍然存在。不确定哪个字符集 pdf 会期望。

以上是关于SQL Server 导出 Blob 损坏所有文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从 blob 文件夹中选择 SQL Server 数据库的所有文件?

MySQL导出数据时提示文件损坏

HIS医院信息系统主服务器RAID5崩溃 硬盘损坏 SQL数据库损坏修复 SQL SERVER数据库修复 备份文件无法还原数据恢复

将 SQL 查询结果作为 txt 文件自动导出到 Azure Blob 存储

sql server2012如何导出数据到dbf

Android 应用离线同步到 Azure SQL Server 和 Blob 存储