使用 NPOI 写入文件
Writing a file using NPOI
尝试从 DLL 执行此操作时,我无法使用 NPOI 将对 xlsx 的更改保存到磁盘。
我有一组数据,目前存储在数据库中,还有一个用于它的自制 ORM。本地开发的 ORM 位于其自己的 DLL 中。我想编写一个实用程序,它使用 ORM 将数据的子集提取到 read/write 它。我正在使用 NPOI (v2.1.3.0) 来完成它。
实用程序调用如下所示:
private void Test_Click(object sender, RoutedEventArgs e)
{
var model = new ExcelDal(this.filename);
model.Clients.Save(new Client {
DateOfBirth = DateTime.Now, DisplayName = "Test", Male = true
});
}
而且我希望我会得到一个 xlsx,其中 sheet 名为 "Client",文本列为 "DateOfBirth"、"DisplayName" 和 "Male".确实创建了一个文件,但尝试打开它失败了。另一方面,如果我用这个替换那个代码,我得到的正是预期的结果:
private void Test_Click(object sender, RoutedEventArgs e)
{
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet = workbook.CreateSheet("Client");
MainWindow.Create(sheet, 0, "DateOfBirth", "DisplayName", "Male");
MainWindow.Create(sheet, 1, "1900/1/1", "Test", "true");
FileMode mode = File.Exists(this.filename) ? FileMode.Truncate : FileMode.Create;
using (FileStream fs = new FileStream(this.filename, mode, FileAccess.ReadWrite))
{
workbook.Write(fs);
}
}
private static void Create(ISheet sheet, int rowNum, params string[] values)
{
IRow row = sheet.CreateRow(rowNum);
for (int i = 0; i < values.Length; i++)
{
ICell cell = row.CreateCell(i);
cell.SetCellValue(values[i]);
}
}
到目前为止尝试的故障排除步骤:
- 将创建的文件重命名为 zip 文件并解压缩,它是一个有效的 zip。
- 压缩文件并将其重命名为 xlsx,我得到一个稍微不同的错误,但它仍然无法打开。
- 一切都是.Net 4.5
- 另一个 SO question 提到在答案中使用 ICreationHelper 来转换字符串值,所以我也尝试了,但它没有改变任何东西。
- 关于 ORM 的一些注意事项,因为包含所有相关代码可能有点矫枉过正。我使用的代码与上面的代码几乎相同;我构建了测试代码以试图弄清楚我做错了什么,但它莫名其妙地起作用了。
这是设置单元格值的代码(请注意,值在实际保存时已经被 toString() 处理):
public void SetValue(IRow row, string column, string value)
{
int columnIndex = this.GetColumnIndex(column);
ICell cell = ColumnMapping.GetOrCreateCell(row, columnIndex);
cell.SetCellValue(value);
}
private static ICell GetOrCreateCell(IRow row, int columnIndex)
{
return row.GetCell(columnIndex) ?? row.CreateCell(columnIndex);
}
保存文件的代码如下所示:
public void Save()
{
FileMode mode = File.Exists(this.filename) ? FileMode.Truncate : FileMode.Create;
using (FileStream fs = new FileStream(this.filename, mode, FileAccess.ReadWrite))
{
this.workbook.Write(fs);
}
}
我无法检测到任何差异。唯一可能的情况是,一种是通过上述 ORM 间接使用 NPOI,另一种是直接使用它。
我无法找到使用 NPOI 可靠地完成此操作的方法。该实用程序创建的文件总是损坏。我切换到 EPPlus for xlsx。生成的代码如下所示:
public void SetValue(int row, string column, string value)
{
row += 2; //EPPlus is 1-index based, and the first row is the heading
int columnIndex = this.GetColumnIndex(column);
this.excelSheet.SetValue(row, columnIndex, value);
}
保存文件的相应代码如下所示:
public void Dispose()
{
//ExcelPackage is gone once it is written out. It must be re-created.
this.excelPackage.SaveAs(new FileInfo(this.filename));
this.excelPackage.Dispose();
}
所以,实现方式是加一个Flush(),把当前的ExcelPackage处理掉,然后把当前内存中的所有ExcelSheet,再从写出来的文件里全部重新初始化。
尝试从 DLL 执行此操作时,我无法使用 NPOI 将对 xlsx 的更改保存到磁盘。
我有一组数据,目前存储在数据库中,还有一个用于它的自制 ORM。本地开发的 ORM 位于其自己的 DLL 中。我想编写一个实用程序,它使用 ORM 将数据的子集提取到 read/write 它。我正在使用 NPOI (v2.1.3.0) 来完成它。
实用程序调用如下所示:
private void Test_Click(object sender, RoutedEventArgs e)
{
var model = new ExcelDal(this.filename);
model.Clients.Save(new Client {
DateOfBirth = DateTime.Now, DisplayName = "Test", Male = true
});
}
而且我希望我会得到一个 xlsx,其中 sheet 名为 "Client",文本列为 "DateOfBirth"、"DisplayName" 和 "Male".确实创建了一个文件,但尝试打开它失败了。另一方面,如果我用这个替换那个代码,我得到的正是预期的结果:
private void Test_Click(object sender, RoutedEventArgs e)
{
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet = workbook.CreateSheet("Client");
MainWindow.Create(sheet, 0, "DateOfBirth", "DisplayName", "Male");
MainWindow.Create(sheet, 1, "1900/1/1", "Test", "true");
FileMode mode = File.Exists(this.filename) ? FileMode.Truncate : FileMode.Create;
using (FileStream fs = new FileStream(this.filename, mode, FileAccess.ReadWrite))
{
workbook.Write(fs);
}
}
private static void Create(ISheet sheet, int rowNum, params string[] values)
{
IRow row = sheet.CreateRow(rowNum);
for (int i = 0; i < values.Length; i++)
{
ICell cell = row.CreateCell(i);
cell.SetCellValue(values[i]);
}
}
到目前为止尝试的故障排除步骤:
- 将创建的文件重命名为 zip 文件并解压缩,它是一个有效的 zip。
- 压缩文件并将其重命名为 xlsx,我得到一个稍微不同的错误,但它仍然无法打开。
- 一切都是.Net 4.5
- 另一个 SO question 提到在答案中使用 ICreationHelper 来转换字符串值,所以我也尝试了,但它没有改变任何东西。
- 关于 ORM 的一些注意事项,因为包含所有相关代码可能有点矫枉过正。我使用的代码与上面的代码几乎相同;我构建了测试代码以试图弄清楚我做错了什么,但它莫名其妙地起作用了。
这是设置单元格值的代码(请注意,值在实际保存时已经被 toString() 处理):
public void SetValue(IRow row, string column, string value)
{
int columnIndex = this.GetColumnIndex(column);
ICell cell = ColumnMapping.GetOrCreateCell(row, columnIndex);
cell.SetCellValue(value);
}
private static ICell GetOrCreateCell(IRow row, int columnIndex)
{
return row.GetCell(columnIndex) ?? row.CreateCell(columnIndex);
}
保存文件的代码如下所示:
public void Save()
{
FileMode mode = File.Exists(this.filename) ? FileMode.Truncate : FileMode.Create;
using (FileStream fs = new FileStream(this.filename, mode, FileAccess.ReadWrite))
{
this.workbook.Write(fs);
}
}
我无法检测到任何差异。唯一可能的情况是,一种是通过上述 ORM 间接使用 NPOI,另一种是直接使用它。
我无法找到使用 NPOI 可靠地完成此操作的方法。该实用程序创建的文件总是损坏。我切换到 EPPlus for xlsx。生成的代码如下所示:
public void SetValue(int row, string column, string value)
{
row += 2; //EPPlus is 1-index based, and the first row is the heading
int columnIndex = this.GetColumnIndex(column);
this.excelSheet.SetValue(row, columnIndex, value);
}
保存文件的相应代码如下所示:
public void Dispose()
{
//ExcelPackage is gone once it is written out. It must be re-created.
this.excelPackage.SaveAs(new FileInfo(this.filename));
this.excelPackage.Dispose();
}
所以,实现方式是加一个Flush(),把当前的ExcelPackage处理掉,然后把当前内存中的所有ExcelSheet,再从写出来的文件里全部重新初始化。