[英]Compress file to bytes for uploading to SQL Server
我正在嘗試將文件壓縮到SQL Server數據庫表中。 我不能確保該工具的用戶在源文件文件夾上具有寫特權,因此我想將該文件加載到內存中,將其壓縮為字節數組並將其插入到我的數據庫中。
這在下面不起作用。
class ZipFileToSql
{
public event MessageHandler Message;
protected virtual void OnMessage(string msg)
{
if (Message != null)
{
MessageHandlerEventArgs args = new MessageHandlerEventArgs();
args.Message = msg;
Message(this, args);
}
}
private int sourceFileId;
private SqlConnection Conn;
private string PathToFile;
private bool isExecuting;
public bool IsExecuting
{
get
{ return isExecuting; }
}
public int SourceFileId
{
get
{ return sourceFileId; }
}
public ZipFileToSql(string pathToFile, SqlConnection conn)
{
isExecuting = false;
PathToFile = pathToFile;
Conn = conn;
}
public void Execute()
{
isExecuting = true;
byte[] data;
byte[] cmpData;
//create temp zip file
OnMessage("Reading file to memory");
FileStream fs = File.OpenRead(PathToFile);
data = new byte[fs.Length];
ReadWholeArray(fs, data);
OnMessage("Zipping file to memory");
MemoryStream ms = new MemoryStream();
GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
zip.Write(data, 0, data.Length);
cmpData = new byte[ms.Length];
ReadWholeArray(ms, cmpData);
OnMessage("Saving file to database");
using (SqlCommand cmd = Conn.CreateCommand())
{
cmd.CommandText = @"MergeFileUploads";
cmd.CommandType = CommandType.StoredProcedure;
//cmd.Parameters.Add("@File", SqlDbType.VarBinary).Value = data;
cmd.Parameters.Add("@File", SqlDbType.VarBinary).Value = cmpData;
SqlParameter p = new SqlParameter();
p.ParameterName = "@SourceFileId";
p.Direction = ParameterDirection.Output;
p.SqlDbType = SqlDbType.Int;
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
sourceFileId = (int)p.Value;
}
OnMessage("File Saved");
isExecuting = false;
}
private void ReadWholeArray(Stream stream, byte[] data)
{
int offset = 0;
int remaining = data.Length;
float Step = data.Length / 100;
float NextStep = data.Length - Step;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", remaining));
remaining -= read;
offset += read;
if (remaining < NextStep)
{
NextStep -= Step;
}
}
}
}
如果將代碼分成較小的塊,則將更易於調試。 在我的示例中,我提供了一種Compress和Decompress方法。 另外,您無需滾動自己的代碼即可從FileStream
讀取所有字節。 您可以簡單地使用File.ReadAllBytes
。 第三,確保在using
語句中包裝實現IDisposable
類。
public void Execute()
{
isExecuting = true;
byte[] data;
byte[] cmpData;
//create temp zip file
OnMessage("Reading file to memory");
byte[] data = File.ReadAllBytes( PathToFile );
OnMessage("Zipping file to memory");
byte[] compressedData = Compress(data);
OnMessage("Saving file to database");
SaveToDatabase( compressedData );
OnMessage("File Saved");
isExecuting = false;
}
private void SaveToDatabase( byte[] data )
{
using ( var cmd = Conn.CreateCommand() )
{
cmd.CommandText = @"MergeFileUploads";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@File", data );
cmd.Parameters["@File"].DbType = DbType.Binary;
cmd.Parameters.Add("@SourceField");
var parameter = cmd.Parameters["@SourceField"];
parameter.DbType = DbType.Int32;
parameter.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
sourceFileId = (int)parameter.Value;
}
}
private static byte[] Compress( byte[] data )
{
var output = new MemoryStream();
using ( var gzip = new GZipStream( output, CompressionMode.Compress, true ) )
{
gzip.Write( data, 0, data.Length );
gzip.Close();
}
return output.ToArray();
}
private static byte[] Decompress( byte[] data )
{
var output = new MemoryStream();
var input = new MemoryStream();
input.Write( data, 0, data.Length );
input.Position = 0;
using ( var gzip = new GZipStream( input, CompressionMode.Decompress, true ) )
{
var buff = new byte[64];
var read = gzip.Read( buff, 0, buff.Length );
while ( read > 0 )
{
output.Write( buff, 0, read );
read = gzip.Read( buff, 0, buff.Length );
}
gzip.Close();
}
return output.ToArray();
}
根據文檔 :
寫入可能不會立即發生,但是會被緩沖,直到達到緩沖區大小或調用Flush或Close方法為止。
因此,您可以嘗試放入zip.Flush()
以確保其刷新流。
另外,將內存流傳ReadWholeArray
方法時,請通過將其Position
屬性設置為0
來倒回該流。
您可能可以簡化執行壓縮和字節數組轉換的代碼,以便遵循以下內容(未經測試,但應該關閉)
MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(PathToFile))
using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress))
{
// This could be replaced with fs.CopyTo(zip); if you are using Framework 4.0
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
zip.Write(buffer, 0, bytesRead);
}
}
// Get the compressed bytes from the memmory stream
byte[] cmpData = ms.ToArray();
謹防。 MemoryStream將用零填充您的輸出數組。 您需要記住其最終位置,然后再調用ToArray()並將數組截斷為適當大小的后綴。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.