Reputation: 51
I have a SQL Server table that contains a varbinary(max)
column. When I query for this data with SSMS, the column looks like this in what I understand is hexadecimal:
0x255044462D312E37
So I copied this data and tried writing it to file like this with C#:
string hexString = "255044462D312E37"
byte[] file = StringToByteArray(hexString);
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
File.WriteAllBytes(@"C:\file.pdf", file);
However I cannot open this file with Adobe, it says the file is damaged.
However, I also have an API that is connected to this Database and that serializes and deserialize responses using Newtonsoft. When it does this, it will convert the varbinary
column to base64. And copying this base and the writing it to disc works just fine like this:
string b64 = "JVBERi0xLjcKJeLjz9M";
byte[] file = Convert.FromBase64String(b64);
File.WriteAllBytes(@"C:\file.pdf", file);
My question is: why can't I convert the hexadecimal string myself?
Upvotes: 4
Views: 9956
Reputation: 1251
You can use stored procedure in sql-server like below :
I can describe this model by one example. if we have table Pictures column [PictureData] and need convert this binary to file use below SP :
Create PROCEDURE [dbo].[usp_ExportImage] (
@PicName NVARCHAR (100)
,@ImageFolderPath NVARCHAR(1000)
,@Filename NVARCHAR(1000)
)
AS
BEGIN
DECLARE @ImageData VARBINARY (max);
DECLARE @Path2OutFile NVARCHAR (2000);
DECLARE @Obj INT
SET NOCOUNT ON
SELECT @ImageData = (
SELECT convert (VARBINARY (max), PictureData, 1)
FROM Pictures
WHERE pictureName = @PicName
);
SET @Path2OutFile = CONCAT (
@ImageFolderPath
,'\'
, @Filename
);
BEGIN TRY
EXEC sp_OACreate 'ADODB.Stream' ,@Obj OUTPUT;
EXEC sp_OASetProperty @Obj ,'Type',1;
EXEC sp_OAMethod @Obj,'Open';
EXEC sp_OAMethod @Obj,'Write', NULL, @ImageData;
EXEC sp_OAMethod @Obj,'SaveToFile', NULL, @Path2OutFile, 2;
EXEC sp_OAMethod @Obj,'Close';
EXEC sp_OADestroy @Obj;
END TRY
BEGIN CATCH
EXEC sp_OADestroy @Obj;
END CATCH
SET NOCOUNT OFF
END
you can use this model for any type of file like JPG,PDF,ZIP and etc.
I hope this helpful for you
Upvotes: 4
Reputation: 131463
varbinary
is a binary type. It stores bytes, not a hex string. 0x255044462D312E37
is how your client tool, eg SSMS or Azure Data Studio display the binary data.
You can read binary data from a query's results through SqlDataReader.GetBytes or as a stream. Copying from the docs :
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(
"SELECT [bindata] FROM [Streams] WHERE [id]=@id", connection))
{
command.Parameters.Add("id", SqlDbType.Int64).Value==1;
await connection.OpenAsync();
using (SqlDataReader reader = await command.ExecuteReaderAsync(
CommandBehavior.SequentialAccess))
{
if (await reader.ReadAsync())
{
if (!(await reader.IsDBNullAsync(0)))
{
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
using (Stream data = reader.GetStream(0))
{
await data.CopyToAsync(file);
}
}
}
}
}
}
ExecuteReaderAsync
must be called with SequentialAccess
, to avoid caching the entire file in memory.
Update
If you can't connect remotely, you can start a Powershell session from SSMS and use Invoke-SqlCmd to execute a query. By default Invoke-SqlCmd
truncates long columns, so you need to use the -MaxBinaryLength
parameter.
Something like this (haven't tested it) :
Invoke-Sqlcmd -Query "SELECT binaryField from someTable" -ServerInstance "."
-MaxBinaryLength 1000000000 | Out-File -FilePath "someFile.pdf"
Upvotes: 5