如何将 base64 编码的图像数据保存到动态命名的子文件夹中的文件中
How do I save base64-encoded image data to a file in a dynamically named subfolder
我有一个 table 包含 base64 编码的 jpeg 以及一些其他数据。 base64 字符串存储在 VARCHAR(MAX)
列中。
如何将这些图像保存到文件夹中的实际文件中,这些文件夹是使用存储过程中 table 中的其他数据动态命名的?
我结合了很多来自不同地方的小技巧找到了答案,想在这里整理一下,因为似乎没有人有完整的过程。
我有两个 table,分别是 Photos
和 PhotoBinary
。 Photos
至少包含一个 PhotoID BIGINT
、Base64
数据 VARCHAR(MAX)
,以及从 NVARCHAR(15)
中获取 FolderName
的内容 - 根据需要增加。我还有一个 BIT
字段来将它们标记为 isProcessed
。 PhotoBinary
有一个 VARBINARY(MAX)
列,应该是空的。
第二个 table 有两个用途,它以二进制格式保存转换后的 base64 编码图像,并允许我解决从 [= 导出数据时 BCP 不允许跳过列的事实42=] 当使用 "format file" 指定列格式时。所以在我的例子中,数据必须单独放在一个 table 中,我确实尝试从视图中获取它,但遇到了上述问题,不允许跳过 id 列。
主存储过程有一个 bcp
命令,该命令依赖于使用以下 SQL 创建的 .fmt
文件。我很确定我必须使用纯文本编辑器编辑生成的文件,以将 8
更改为 0
,指示 SQLBINARY
之后的前缀长度。我不能只在主存储过程中的命令上使用 -n
开关,因为它导致将 8 字节前缀放入生成的文件中,这使其成为无效的 jpeg。所以,我使用编辑过的格式文件来解决这个问题。
DECLARE @command VARCHAR(4000);
SET @command = 'bcp DB.dbo.PhotoBinary format nul -T -n -f "A:\pathto\photobinary.fmt"';
EXEC xp_cmdshell @command;
然后我在存储过程中有以下内容,我 运行 将图像导出到适当的文件夹中:
DECLARE @command VARCHAR(4000),
@photoId BIGINT,
@imageFileName VARCHAR(128),
@folderName NVARCHAR(15),
@basePath NVARCHAR(500),
@fullPath NVARCHAR(500),
@dbServerName NVARCHAR(100);
DECLARE @directories TABLE (directory nvarchar(255), depth INT);
-- The location of the output folder
SET @basePath = '\server\share';
-- The server that the photobinary db is on
SET @dbServerName = 'localhost';
-- @basePath values, get the folders already in the output folder
INSERT INTO @directories(directory, depth) EXEC master.sys.xp_dirtree @basePath;
-- Cursor for each image in table that hasn't already been exported
DECLARE photo_cursor CURSOR FOR
SELECT PhotoID,
'some_image_' + CAST(PhotoID AS NVARCHAR) + '.jpg',
FolderName
FROM dbo.Photos
WHERE isProcessed = 0;
OPEN photo_cursor
FETCH NEXT FROM photo_cursor
INTO @photoId,
@imageFileName,
@folderName;
WHILE (@@FETCH_STATUS = 0) -- Cursor loop
BEGIN
-- Create the @basePath directory
IF NOT EXISTS (SELECT * FROM @directories WHERE directory = @folderName)
BEGIN
SET @fullPath = @basePath + '\' + @folderName;
EXEC master.dbo.xp_create_subdir @fullPath;
END
-- move and convert the base64 encoded image to a separate table in binary format
-- it should be the only row in the table
INSERT INTO DB.dbo.PhotoBinary (PhotoBinary)
SELECT CAST(N'' AS xml).value('xs:base64Binary(sql:column("Base64"))', 'varbinary(max)')
FROM DB.dbo.Photos
WHERE PhotoID = @photoId;
-- This command uses the command-line BCP tool to "bulk export" the image data in binary to an "archive" file that just happens to be a jpg
SET @command = 'bcp "SELECT TOP 1 PhotoBinary FROM DB.dbo.PhotoBinary" queryout "' + @basePath + '\' + @folderName + '\' + @imageFileName + '" -T -S ' + @dbServerName + ' -f "A:\pathto\photobinary.fmt"';
EXEC xp_cmdshell @command;
-- clean up the photo data
DELETE FROM DB.dbo.PhotoBinary;
-- mark photo as processed
UPDATE DB.dbo.Photos SET isProcessed = 1 WHERE PhotoID = @photoId;
FETCH NEXT FROM photo_cursor
INTO @photoId,
@imageFileName,
@folderName;
END -- cursor loop
CLOSE photo_cursor
DEALLOCATE photo_cursor
我有一个 table 包含 base64 编码的 jpeg 以及一些其他数据。 base64 字符串存储在 VARCHAR(MAX)
列中。
如何将这些图像保存到文件夹中的实际文件中,这些文件夹是使用存储过程中 table 中的其他数据动态命名的?
我结合了很多来自不同地方的小技巧找到了答案,想在这里整理一下,因为似乎没有人有完整的过程。
我有两个 table,分别是 Photos
和 PhotoBinary
。 Photos
至少包含一个 PhotoID BIGINT
、Base64
数据 VARCHAR(MAX)
,以及从 NVARCHAR(15)
中获取 FolderName
的内容 - 根据需要增加。我还有一个 BIT
字段来将它们标记为 isProcessed
。 PhotoBinary
有一个 VARBINARY(MAX)
列,应该是空的。
第二个 table 有两个用途,它以二进制格式保存转换后的 base64 编码图像,并允许我解决从 [= 导出数据时 BCP 不允许跳过列的事实42=] 当使用 "format file" 指定列格式时。所以在我的例子中,数据必须单独放在一个 table 中,我确实尝试从视图中获取它,但遇到了上述问题,不允许跳过 id 列。
主存储过程有一个 bcp
命令,该命令依赖于使用以下 SQL 创建的 .fmt
文件。我很确定我必须使用纯文本编辑器编辑生成的文件,以将 8
更改为 0
,指示 SQLBINARY
之后的前缀长度。我不能只在主存储过程中的命令上使用 -n
开关,因为它导致将 8 字节前缀放入生成的文件中,这使其成为无效的 jpeg。所以,我使用编辑过的格式文件来解决这个问题。
DECLARE @command VARCHAR(4000);
SET @command = 'bcp DB.dbo.PhotoBinary format nul -T -n -f "A:\pathto\photobinary.fmt"';
EXEC xp_cmdshell @command;
然后我在存储过程中有以下内容,我 运行 将图像导出到适当的文件夹中:
DECLARE @command VARCHAR(4000),
@photoId BIGINT,
@imageFileName VARCHAR(128),
@folderName NVARCHAR(15),
@basePath NVARCHAR(500),
@fullPath NVARCHAR(500),
@dbServerName NVARCHAR(100);
DECLARE @directories TABLE (directory nvarchar(255), depth INT);
-- The location of the output folder
SET @basePath = '\server\share';
-- The server that the photobinary db is on
SET @dbServerName = 'localhost';
-- @basePath values, get the folders already in the output folder
INSERT INTO @directories(directory, depth) EXEC master.sys.xp_dirtree @basePath;
-- Cursor for each image in table that hasn't already been exported
DECLARE photo_cursor CURSOR FOR
SELECT PhotoID,
'some_image_' + CAST(PhotoID AS NVARCHAR) + '.jpg',
FolderName
FROM dbo.Photos
WHERE isProcessed = 0;
OPEN photo_cursor
FETCH NEXT FROM photo_cursor
INTO @photoId,
@imageFileName,
@folderName;
WHILE (@@FETCH_STATUS = 0) -- Cursor loop
BEGIN
-- Create the @basePath directory
IF NOT EXISTS (SELECT * FROM @directories WHERE directory = @folderName)
BEGIN
SET @fullPath = @basePath + '\' + @folderName;
EXEC master.dbo.xp_create_subdir @fullPath;
END
-- move and convert the base64 encoded image to a separate table in binary format
-- it should be the only row in the table
INSERT INTO DB.dbo.PhotoBinary (PhotoBinary)
SELECT CAST(N'' AS xml).value('xs:base64Binary(sql:column("Base64"))', 'varbinary(max)')
FROM DB.dbo.Photos
WHERE PhotoID = @photoId;
-- This command uses the command-line BCP tool to "bulk export" the image data in binary to an "archive" file that just happens to be a jpg
SET @command = 'bcp "SELECT TOP 1 PhotoBinary FROM DB.dbo.PhotoBinary" queryout "' + @basePath + '\' + @folderName + '\' + @imageFileName + '" -T -S ' + @dbServerName + ' -f "A:\pathto\photobinary.fmt"';
EXEC xp_cmdshell @command;
-- clean up the photo data
DELETE FROM DB.dbo.PhotoBinary;
-- mark photo as processed
UPDATE DB.dbo.Photos SET isProcessed = 1 WHERE PhotoID = @photoId;
FETCH NEXT FROM photo_cursor
INTO @photoId,
@imageFileName,
@folderName;
END -- cursor loop
CLOSE photo_cursor
DEALLOCATE photo_cursor