如何将base64编码的图像数据保存到动态命名的子文件夹中的文件中

时间:2016-02-26 09:29:42

标签: sql-server stored-procedures sql-server-2005 base64 jpeg

我有一个包含base64编码的jpeg的表以及一些其他数据。 base64字符串存储在VARCHAR(MAX)列中。

如何将这些图像保存到文件夹中的实际文件中,这些文件是使用存储过程中表中的其他数据动态命名的?

1 个答案:

答案 0 :(得分:0)

我通过结合来自不同地方的许多小技巧找到答案,并希望在这里整理它们,因为似乎没有人有完整的过程。

我有两个表,分别叫PhotosPhotoBinaryPhotos至少包含PhotoID BIGINTBase64数据VARCHAR(MAX),以及可以根据需要增加FolderName - NVARCHAR(15)的内容。我还有BIT字段将其标记为isProcessedPhotoBinary只有一个VARBINARY(MAX)列,应该为空。

第二个表有两个目的,它以二进制格式保存转换后的base64编码图像,并允许我解决在使用"时从表中导出数据时BCP不会跳过列的事实。格式文件"指定列格式。所以在我的情况下,数据必须单独存在于一个表中,我确实尝试从视图中获取它,但是上述问题不允许跳过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