带有 NPOI 的 .xlsx 文件损坏问题 - Excel 无法打开文件“file.xlsx”,因为文件格式或文件扩展名无效
Problematic corruption of .xlsx files with NPOI - Excel cannot open the file 'file.xlsx" because the file format or file extension is not valid
在读取或修改一些用户创建的 .xlsx 文件时,我收到以下错误消息:
We found a problem with some content in 'test.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes.
单击“是”会收到另一条消息:
Excel cannot open the file 'test.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.
问题 .xlsx 文件示例 here(放入 NPOI 之前)。
这是同一个文件,在使用 iWorkbook.Write(filestream);
here.
读取和写回后现在已损坏
我使用以下代码创建新的 .xlsx 文件没有问题:
string newPath = @"C:\MyPath\test.xlsx";
using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write))
{
IWorkbook wb = new XSSFWorkbook();
wb.CreateSheet();
ISheet s = wb.GetSheetAt(0);
IRow r = s.CreateRow(0);
r.CreateCell(0);
ICell c = r.GetCell(0);
c.SetCellValue("test");
wb.Write(fs);
fs.Close();
}
效果不错。
即使打开其中一个有问题的子 .xlsx 文件,将其设置为 IWorkbook 并将其写回文件也能正常工作:
string newPath = @"C:\MyPath\test.xlsx";
using (FileStream fs = new FileStream(newPath, FileMode.Open, FileAccess.ReadWrite))
{
IWorkbook wb = new XSSFWorkbook(fs);
wb.Write(fs);
fs.Close();
}
但是,在 运行 通过从中读取的代码获取 ISheets、IRows、ICells 等之后...它损坏了 .xlsx 文件。 即使我专门删除了修改工作簿的任何内容。 没有使用 NPOI 创建、设置、样式等。
我不能真正包含我的代码,因为它只会让人困惑,但为了完整起见,我在这个测试期间实际上只使用了 NPOI 的以下类型和函数:
IWorkbook
XSSFWorkbook
ISheet
IRow
ICell
.GetSheetAt
.GetRow
.GetCell
.LastRowNum
所以其中之一会导致腐败。我想最终再次设置值并让它像我对 .xls 一样工作。
有人遇到过这种情况吗?哪些 NPOI 职能可能导致腐败?任何输入将不胜感激。
编辑:使用 NPOI v2.2.1。
我认为问题在于您正在读取和写入同一个 FileStream
。您应该使用单独的流进行读取和写入。
像这样尝试:
string newPath = @"C:\MyPath\test.xlsx";
// read the workbook
IWorkbook wb;
using (FileStream fs = new FileStream(newPath, FileMode.Open, FileAccess.Read))
{
wb = new XSSFWorkbook(fs);
}
// make changes
ISheet s = wb.GetSheetAt(0);
IRow r = s.GetRow(0) ?? s.CreateRow(0);
ICell c = r.GetCell(1) ?? r.CreateCell(1);
c.SetCellValue("test2");
// overwrite the workbook using a new stream
using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write))
{
wb.Write(fs);
}
我遇到了同样的问题。就我而言,问题不在于 NPOI 本身,而在于它的依赖项 SharpZipLib。
我使用了 NPOI 2.3.0 和 SharpZipLib 1.0.0。并且给出了与您的情况相同的错误。生成的 Excel 大小为 0 字节。
我在使用 NPOI(服务层)和 MVC 项目(我这里也有 SharpZipLib 的包)的项目中将 SharpZipLib 降级回 0.86.0。
我还在 web.config 中手动删除了之前为 SharpZipLib 创建的程序集依赖项:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
.......
<dependentAssembly>
<assemblyIdentity name="ICSharpCode.SharpZipLib" publicKeyToken="1b03e6acf1164f73" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.999" newVersion="1.0.0.999" />
</dependentAssembly>
</assemblyBinding>
我希望这对某人有所帮助。
我在尝试将 excel 文件写入内存流然后通过我的 .net Core 控制器下载时遇到了同样的错误。
这段代码是我的问题(此时,workbook
包含我创建的 NPOI excel 文件):
var fileName = $"export.xlsx";
var mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
MemoryStream stream = new();
workbook.Write(stream);
byte[] output = stream.GetBuffer();
return File(output, mimeType, fileName);
问题出在这一行:
byte[] output = stream.GetBuffer();
那一行给了我一个包含 excel 文件内容的字节数组,但我没有意识到 GetBuffer 不仅返回代表 excel 文件的字节数组,而且字节数组的剩余分配内存。
我用这个替换了那行:
byte[] output = stream.ToArray();
生活也很美好。
写回文件时,一定要用Create
as FileMode
的方法。如果您使用 Open
,该文件将 损坏 因为它将在旧文件的末尾连接新文件。
IWorkbook workbook;
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
workbook = new XSSFWorkbook(file);
}
// do things to workbook...
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(file);
}
在读取或修改一些用户创建的 .xlsx 文件时,我收到以下错误消息:
We found a problem with some content in 'test.xlsx'. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes.
单击“是”会收到另一条消息:
Excel cannot open the file 'test.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file.
问题 .xlsx 文件示例 here(放入 NPOI 之前)。
这是同一个文件,在使用 iWorkbook.Write(filestream);
here.
我使用以下代码创建新的 .xlsx 文件没有问题:
string newPath = @"C:\MyPath\test.xlsx";
using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write))
{
IWorkbook wb = new XSSFWorkbook();
wb.CreateSheet();
ISheet s = wb.GetSheetAt(0);
IRow r = s.CreateRow(0);
r.CreateCell(0);
ICell c = r.GetCell(0);
c.SetCellValue("test");
wb.Write(fs);
fs.Close();
}
效果不错。
即使打开其中一个有问题的子 .xlsx 文件,将其设置为 IWorkbook 并将其写回文件也能正常工作:
string newPath = @"C:\MyPath\test.xlsx";
using (FileStream fs = new FileStream(newPath, FileMode.Open, FileAccess.ReadWrite))
{
IWorkbook wb = new XSSFWorkbook(fs);
wb.Write(fs);
fs.Close();
}
但是,在 运行 通过从中读取的代码获取 ISheets、IRows、ICells 等之后...它损坏了 .xlsx 文件。 即使我专门删除了修改工作簿的任何内容。 没有使用 NPOI 创建、设置、样式等。
我不能真正包含我的代码,因为它只会让人困惑,但为了完整起见,我在这个测试期间实际上只使用了 NPOI 的以下类型和函数:
IWorkbook
XSSFWorkbook
ISheet
IRow
ICell
.GetSheetAt
.GetRow
.GetCell
.LastRowNum
所以其中之一会导致腐败。我想最终再次设置值并让它像我对 .xls 一样工作。
有人遇到过这种情况吗?哪些 NPOI 职能可能导致腐败?任何输入将不胜感激。
编辑:使用 NPOI v2.2.1。
我认为问题在于您正在读取和写入同一个 FileStream
。您应该使用单独的流进行读取和写入。
像这样尝试:
string newPath = @"C:\MyPath\test.xlsx";
// read the workbook
IWorkbook wb;
using (FileStream fs = new FileStream(newPath, FileMode.Open, FileAccess.Read))
{
wb = new XSSFWorkbook(fs);
}
// make changes
ISheet s = wb.GetSheetAt(0);
IRow r = s.GetRow(0) ?? s.CreateRow(0);
ICell c = r.GetCell(1) ?? r.CreateCell(1);
c.SetCellValue("test2");
// overwrite the workbook using a new stream
using (FileStream fs = new FileStream(newPath, FileMode.Create, FileAccess.Write))
{
wb.Write(fs);
}
我遇到了同样的问题。就我而言,问题不在于 NPOI 本身,而在于它的依赖项 SharpZipLib。
我使用了 NPOI 2.3.0 和 SharpZipLib 1.0.0。并且给出了与您的情况相同的错误。生成的 Excel 大小为 0 字节。 我在使用 NPOI(服务层)和 MVC 项目(我这里也有 SharpZipLib 的包)的项目中将 SharpZipLib 降级回 0.86.0。
我还在 web.config 中手动删除了之前为 SharpZipLib 创建的程序集依赖项:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
.......
<dependentAssembly>
<assemblyIdentity name="ICSharpCode.SharpZipLib" publicKeyToken="1b03e6acf1164f73" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.999" newVersion="1.0.0.999" />
</dependentAssembly>
</assemblyBinding>
我希望这对某人有所帮助。
我在尝试将 excel 文件写入内存流然后通过我的 .net Core 控制器下载时遇到了同样的错误。
这段代码是我的问题(此时,workbook
包含我创建的 NPOI excel 文件):
var fileName = $"export.xlsx";
var mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
MemoryStream stream = new();
workbook.Write(stream);
byte[] output = stream.GetBuffer();
return File(output, mimeType, fileName);
问题出在这一行:
byte[] output = stream.GetBuffer();
那一行给了我一个包含 excel 文件内容的字节数组,但我没有意识到 GetBuffer 不仅返回代表 excel 文件的字节数组,而且字节数组的剩余分配内存。
我用这个替换了那行:
byte[] output = stream.ToArray();
生活也很美好。
写回文件时,一定要用Create
as FileMode
的方法。如果您使用 Open
,该文件将 损坏 因为它将在旧文件的末尾连接新文件。
IWorkbook workbook;
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
workbook = new XSSFWorkbook(file);
}
// do things to workbook...
using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(file);
}