使用NPOI破坏.xlsx文件的问题 - Excel无法打开文件'file.xlsx',因为文件格式或文件扩展名无效

jus*_*tus 3 c# excel xlsx apache-poi npoi

阅读或修改一些用户创建的.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.
Run Code Online (Sandbox Code Playgroud)

单击是获取另一条消息:

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.
Run Code Online (Sandbox Code Playgroud)

此处出现问题.xlsx文件的示例(在放入NPOI之前).

下面是相同的文件,现在损坏的读取和写回后iWorkbook.Write(filestream); 这里.

使用以下代码创建新的.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();
}
Run Code Online (Sandbox Code Playgroud)

这很好.

即使打开一个问题子.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();
}
Run Code Online (Sandbox Code Playgroud)

但是,在运行从中读取的代码之后,获取ISheets,IRows,ICell等等......它会破坏.xlsx文件.即使我专门删除了修改工作簿的任何内容.使用NPOI不创建,设置,样式等.

我不能真正包含我的代码,因为它只会让人感到困惑,但为了完整起见,我在这次测试中只使用了NPOI的以下类型和函数:

IWorkbook
XSSFWorkbook
ISheet
IRow
ICell
.GetSheetAt
.GetRow
.GetCell
.LastRowNum
Run Code Online (Sandbox Code Playgroud)

所以其中一个会导致腐败.我想最终再次设置值,让它像我对.xls一样工作.

有没有人经历过这个?什么是可能导致腐败的NPOI功能?任何输入将不胜感激.

编辑:使用NPOI v2.2.1.

Bri*_*ers 6

我认为问题在于你正在阅读和写作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);
}
Run Code Online (Sandbox Code Playgroud)


bir*_*win 5

我在尝试将 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);
Run Code Online (Sandbox Code Playgroud)

问题是这一行:

byte[] output = stream.GetBuffer();
Run Code Online (Sandbox Code Playgroud)

该行给了我一个包含 excel 文件内容的字节数组,但我没有意识到 GetBuffer 不仅返回表示 excel 文件的字节数组,还返回为字节数组分配的剩余内存。

我用以下内容替换了该行:

byte[] output = stream.ToArray();
Run Code Online (Sandbox Code Playgroud)

生活是美好的。