走訪資料夾及Web下載檔案(zip)
最近遇到一個情況,是對方要求一個Excel有多個Sheet的時候,要產生多個檔案。
那網路上查過之後發現,Response出來的檔案一次只能有一個。
也就是說Excel有兩個Sheet的時候,就算我產生了兩個pdf,也沒辦法下載兩個pdf。
因此還需要打包成zip檔案下載。
----------------------------------------------------------------------------完整程式部分
// 1.------------- 建立檔案名稱以及走訪目標區域
//zip檔案名稱 這段主要是在取zip等等的名稱,因為有檔案傳入,因此直接取xls檔案位置的資料 xlsfilepath 的名字 without 副檔名後再加上.zip 這段單純是在取名字而已
string zipSteamName = Path.Combine(Path.GetDirectoryName(xlsfilepath), Path.GetFileNameWithoutExtension(xlsfilepath) + ".zip");
//這段的目的在於鎖定走訪的路徑
//取得目標路徑 目標路徑為pdf資料夾
DirectoryInfo di = new DirectoryInfo(pathPdf);
//取得目標pdf資料夾內pdf資料陣列
FileInfo[] files = di.GetFiles();
//建立zip檔案 若有則update
using (var filestream = new FileStream(zipSteamName, FileMode.OpenOrCreate))
{
//建立zip檔案內資料 update新增資料
using (var archive = new ZipArchive(filestream, ZipArchiveMode.Update, true))
{
//走訪file資料夾
foreach (var fileinfo in files)
{
//取得新檔案 f = file 內含pdf資料夾內資料走訪
FileStream f = new FileStream(fileinfo.FullName, FileMode.Open, FileAccess.Read);
//取得filestream 成 byte array
byte[] xlsxBytes = BinaryReadToEnd(f);
//建立zip內檔案 含名稱及型態
var zipArchiveEntry = archive.CreateEntry(fileinfo.Name, CompressionLevel.Fastest);
//寫資料進入zip內檔案
using (var zipStream = zipArchiveEntry.Open())
{
zipStream.Write(xlsxBytes, 0, xlsxBytes.Length);
}
//歸還空間 這邊不歸還的話沒辦法關掉file 會導致file卡死無法操作
f.Dispose();
f.Close();
}
//歸還空間
archive.Dispose();
};
//歸還空間
filestream.Dispose();
filestream.Close();
};
// 這邊我本身是偷懶 直接使用xls的資料夾來進行壓縮 反正裡面的資料當初專案設定的時候也是要刪除的
//清除xls檔案 方便產生zip
System.IO.File.Delete(xlsfilepath);
//切換至xls資料夾走訪
di = new DirectoryInfo(pathXls);
files = di.GetFiles();
// 2.-------------------------------------------- 網路下載部分
//清空Response
Response.Clear();
//建立標頭及type
Response.AddHeader("Content-Disposition", "attachment;filename=" + Path.GetFileName(zipSteamName));
//Type為資料orZip檔案
Response.ContentType = "application/zip,application/octet-stream";
//走訪xls資料夾內資料,若資料夾中有其他資料則可能造成產生的zip檔案產生問題
foreach (var fileinfo in files)
{
//取得新檔案 f = file 內含pdf資料夾內資料走訪
FileStream f = new FileStream(fileinfo.FullName, FileMode.Open, FileAccess.Read);
//取得filestream 成 byte array
byte[] xlsxBytes = BinaryReadToEnd(f);
//寫入Response中 用於產生檔案
Response.OutputStream.Write(xlsxBytes, 0, xlsxBytes.Length);
//歸還空間 同樣上述道理
f.Dispose();
f.Close();
//清除已經產生的zip檔案 歸還空間
fileinfo.Delete();
}
//寫入Response
//清空並歸還空間
Response.OutputStream.Flush();
Response.OutputStream.Close();
Response.Flush();
// 3. ----------------------------------- 取得Byte[]部分
public static byte[] BinaryReadToEnd(Stream stream)
{
//目前stream位置
long originalPosition = 0;
//若stream可支援搜尋的話
//檢查是否有選定從某個點開始
if (stream.CanSeek)
{
//目前位置 = stream位置
originalPosition = stream.Position;
//stream 歸零
stream.Position = 0;
}
try
{
//byte array儲存區
byte[] readBuffer = new byte[4096];
//目前讀取位置 起始點
int totalBytesRead = 0;
//目前讀取位置 結束點
int bytesRead;
//一次抓4096個長度 抓到-1的時候停止
//計算目前讀到哪一位數 從totalBytesRead開始讀 讀 readbuffer - 曾經讀過的長度
//也就是從 array0開始 讀取 4096個 因此是 0 ~ 4095陣列有值
//如果讀取長度超過的話則不會讀取值
//如一個長度為10000的資料 讀取長度為 16000 讀取還是只會回饋 10000 而非 16000
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
//目前讀到的長度
totalBytesRead += bytesRead;
//假如長度相同的話 代表還沒讀滿
if (totalBytesRead == readBuffer.Length)
{
//取目前讀的下一個值
int nextByte = stream.ReadByte();
//計算目前要讀的下一個是否有值 沒值是-1
if (nextByte != -1)
{
//建立一個大兩倍的空間 不夠大就繼續兩倍成長空間來讀取程式
byte[] temp = new byte[readBuffer.Length * 2];
//從readBuffer 0位開始複製整個readbuffer到temp中
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
//在上一個空間最大值中塞入一位byte
//(原理是因為 4096長度的空間是為 0 ~ 4095 因此在4096塞入一位 變成4097長度)
//且因為讀取了值 因此不寫入的話會遺漏
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
//複製temp的空間大小給readbuffer
readBuffer = temp;
//因為readbuffer有多加一位 因此+1
totalBytesRead++;
}
}
}
//輸出readbuffer
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
//建立一個buffer 他的長度為剛剛測定的全長
buffer = new byte[totalBytesRead];
//複製readBuffer的資料從頭到尾進入buffer內
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
//若可以搜尋的話
if (stream.CanSeek)
{
//資料流位置 = 目前stream位置
//更新stream位置回最初位置
stream.Position = originalPosition;
}
}
}
參考:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
https://stackoverflow.com/questions/20100445/zip-file-content-type-for-http-request
https://dotblogs.com.tw/gelis/2016/09/04/161341
https://docs.microsoft.com/zh-tw/dotnet/api/system.io.compression.zipfile?view=net-6.0
https://stackoverflow.com/questions/834527/how-do-i-generate-and-send-a-zip-file-to-a-user-in-c-sharp-asp-net
留言
張貼留言