关于修改压缩包内的文件(Excel…)内容的解决方法
前提:
💩 如果能在压缩前就修改完成就不需要修改压缩包内的文件
💩 如果能在压缩前就修改完成就不需要修改压缩包内的文件
💩 如果能在压缩前就修改完成就不需要修改压缩包内的文件
🌵 场景:
A接口的功能是将用户上传的Excel按指定的行列拆分成多个Excel。(同事写的,一时难以看懂)
记录会存到表中,同时拆分完成的多个Excel会被放入一个压缩文件中保存到某一路径。
压缩包供用户下载。
需求很简单:压缩包内的Excel设置自动列宽
- 解决方法一:
在他的接口逻辑里直接在拆分后直接设置自动列宽…(不如直接让他改)
- 解决方法二:
在他下载对应压缩包的接口中直接修改压缩包内的Excel文件,这种方法比较直接且好像可行。
开始
压缩包内的excel没有设置自动列宽,如图:
获取压缩包内的文件,设置自动列宽很简单,具体实现如下:
static void Main(string[] args)
{
string zipSavePath = @"E:\资料拆分\Zip14";
string fileName = $@"TestZip";
//打开目标压缩包
using (var archive = ZipFile.Open($"{ zipSavePath }\\{ fileName }.zip", ZipArchiveMode.Update))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Stream stream = entry.Open();
XSSFWorkbook wb = new XSSFWorkbook(stream);
ISheet sheet = wb.GetSheetAt(0);
int col_num = 0;
try
{
while (sheet.GetRow(0).GetCell(col_num) != null)
col_num++;
}
catch (Exception e)
{
// DoNothing
}
//找到存在的列,设置自动宽度
for (int i = 0; i <= col_num; i++)
sheet.AutoSizeColumn(i);
MemoryStream ms = new MemoryStream();
wb.Write(ms, true);
//保存后再把流塞回去
using (Stream entryStream = entry.Open())
{
ms.Seek(0, SeekOrigin.Begin);
ms.CopyTo(entryStream);
ms.Close();
}
}
}
using FileStream fs = new FileStream($"{ zipSavePath }\\{ fileName }.zip", FileMode.Open, FileAccess.ReadWrite);
byte[] buffer = new byte[fs.Length + 1];
fs.Read(buffer, 0, (int)fs.Length);
}
}
但这种方法会造成Excel文档损坏
虽然在Excel自动的修复后可以使用,但终究是不能使用这种方法的。
要避免这种情况,你必须新建压缩包,把Excel一个个修改后直接存在新的压缩包里,毕竟上面的代码改动后还是被流塞进了原来的文件,故会造成一些不知名的损坏。
改良代码:
static void Main(string[] args)
{
string zipSavePath = @"E:\资料拆分\Zip14";
string fileName = $@"TestZip";
//防止多从调用创建重复文件
File.Delete($@"{ zipSavePath }\\{ fileName + "back" }.zip");
//创建新的压缩包
ZipArchive NewZip = ZipFile.Open($@"{ zipSavePath }\\{ fileName + "back" }.zip",ZipArchiveMode.Create);
using (var archive = ZipFile.Open($"{ zipSavePath }\\{ fileName }.zip", ZipArchiveMode.Update))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Stream stream = entry.Open();
XSSFWorkbook wb = new XSSFWorkbook(stream);
ISheet sheet = wb.GetSheetAt(0);
int col_num = 0;
try
{
while (sheet.GetRow(0).GetCell(col_num) != null)
col_num++;
}
catch (Exception e)
{
// DoNothing
}
for (int i = 0; i <= col_num; i++)
sheet.AutoSizeColumn(i);
MemoryStream ms = new MemoryStream();
wb.Write(ms, true);
ZipArchiveEntry newNode = NewZip.CreateEntry(entry.Name);
//将设置完成的Excel丢到新的压缩包内
using (Stream entryStream = newNode.Open())
{
ms.Seek(0, SeekOrigin.Begin);
ms.CopyTo(entryStream);
ms.Close();
}
}
}
NewZip.Dispose();
using FileStream fs = new FileStream($"{ zipSavePath }\\{ fileName+"back" }.zip", FileMode.Open, FileAccess.ReadWrite);
byte[] buffer = new byte[fs.Length + 1];
fs.Read(buffer, 0, (int)fs.Length);
}
如果在要在接口中返回压缩包则直接将新压缩包返回即可。