- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我尝试将所有工作表从一个工作簿复制到另一个工作簿。问题是,如果我通过 FileInputStreams 读取工作簿,它可以正常工作,但它不适用于文件对象。
考虑以下方法:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataConsolidateFunction;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFPivotTable;
import org.apache.poi.xssf.usermodel.XSSFSheet;
public void copyAllSheetsAcrossWorkbook(String oldWorkbook, String newWorkbook)
throws EncryptedDocumentException, InvalidFormatException, IOException {
FileInputStream fisOld = null;
FileInputStream fisNew = null;
Workbook oldWB = null;
Workbook newWB = null;
FileOutputStream fileOut = null;
System.out.println("oldWorkbook: " + oldWorkbook);
System.out.println("newWorkbook: " + newWorkbook);
fisOld = new FileInputStream(oldWorkbook);
fisNew = new FileInputStream(newWorkbook);
// THIS WORKS
// oldWB = WorkbookFactory.create(fisOld);
// newWB = WorkbookFactory.create(fisNew);
// THIS DOES NOT WORK
oldWB = WorkbookFactory.create(new File(oldWorkbook));
newWB = WorkbookFactory.create(new File(newWorkbook));
if (newWB == null) {
System.out.println("newWB is null");
}
// CellStyle newStyle = newWB.createCellStyle();
Row row;
Cell cell;
copiedSheets = new ArrayList<String>();
for (int i = 0; i < oldWB.getNumberOfSheets(); i++) {
XSSFSheet sheetFromOldWB = (XSSFSheet) oldWB.getSheetAt(i);
String sheetNameFromOldWB = sheetFromOldWB.getSheetName();
XSSFSheet sheetForNewWB = (XSSFSheet) newWB.getSheet(sheetNameFromOldWB);
if (sheetForNewWB != null) {
int sheetIndex = newWB.getSheetIndex(sheetNameFromOldWB);
newWB.removeSheetAt(sheetIndex);
}
LOGGER.info("Copying to new Workbook: " + sheetNameFromOldWB);
sheetForNewWB = (XSSFSheet) newWB.createSheet(sheetFromOldWB.getSheetName());
for (int rowIndex = 0; rowIndex < sheetFromOldWB.getPhysicalNumberOfRows(); rowIndex++) {
row = sheetForNewWB.createRow(rowIndex);
for (int colIndex = 0; colIndex < sheetFromOldWB.getRow(rowIndex).getPhysicalNumberOfCells(); colIndex++) {
cell = row.createCell(colIndex);
// get cell from old WB's sheet and when cell is null, return as blank cells.
Cell c = sheetFromOldWB.getRow(rowIndex).getCell(colIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
// Below is where all the copying is happening.
// CellStyle origStyle = c.getCellStyle();
// newStyle.cloneStyleFrom(origStyle);
// cell.setCellStyle(newStyle);
switch (c.getCellTypeEnum()) {
case STRING:
cell.setCellValue(c.getRichStringCellValue().getString());
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
cell.setCellValue(c.getDateCellValue());
} else {
cell.setCellValue(c.getNumericCellValue());
}
break;
case BOOLEAN:
cell.setCellValue(c.getBooleanCellValue());
break;
case FORMULA:
cell.setCellFormula(c.getCellFormula());
break;
default:
break;
}
}
}
copiedSheets.add(oldWB.getSheetName(i));
}
fileOut = new FileOutputStream(newWorkbook);
newWB.write(fileOut); // <------ HERE I GET NULLPOINTEREXCEPTION
fisOld.close();
fisNew.close();
oldWB.close();
fileOut.close();
newWB.close();
我在 newWB.write(fileOut);
处得到以下异常:
Exception in thread "main" org.apache.poi.POIXMLException: java.lang.NullPointerException
at org.apache.poi.POIXMLDocument.getProperties(POIXMLDocument.java:168)
at org.apache.poi.POIXMLDocument.write(POIXMLDocument.java:246)
at com.capgemini.toolkit.App.copyAllSheetsAcrossWorkbook(App.java:263)
at com.capgemini.toolkit.App.main(App.java:58)
Caused by: java.lang.NullPointerException
at org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream.read(ZipSecureFile.java:210)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
at org.apache.poi.util.DocumentHelper.readDocument(DocumentHelper.java:140)
at org.apache.poi.POIXMLTypeLoader.parse(POIXMLTypeLoader.java:143)
at org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument$Factory.parse(Unknown Source)
at org.apache.poi.POIXMLProperties.<init>(POIXMLProperties.java:78)
at org.apache.poi.POIXMLDocument.getProperties(POIXMLDocument.java:166)
... 3 more
在 POI 文档中,总是提到更好地使用 File
对象,因为它可以降低内存消耗。这就是为什么我想知道为什么它不适用于 File
对象。
为了测试,这是在主要方法中运行的唯一方法,我使用了 2 个带有一些虚拟数据的新 Excel 文件 (.xlsx)。
有人知道为什么它不能与 File
对象一起使用吗?我做错了什么吗?
仅供引用:我正在使用 POI 3.16。
最佳答案
使用 File
而不是 FileInputStream
打开 Workbook
可以减少内存占用,因为如果是 XSSF
(*.xlsx
), ZipPackage将直接从 *.xlsx
文件打开,而不是将整个 ZIP
内容读入内存。
但这也意味着,ZipPackage
会打开文件,直到 Workbook
关闭。因此,在 Workbook
关闭之前,没有任何内容可以同时写入该文件。因此,由于无法使用 File
将 Workbook
内容写回到打开 Workbook
的同一文件中相反,如果您只想从该 Workbook
中读取,则用于打开 Workbook
的 FileInputStream
就可以了。但如果你想读取和写入同一个文件,它就不起作用了。然后需要 FileInputStream
和 FileOutputStream
。
因此,在您的情况下,您尝试从 File
读取 Workbook newWB
,然后使用 Workbook
将 Workbook
写入同一文件
fileOut = new FileOutputStream(newWorkbook);
newWB.write(fileOut);
文件已经打开。这失败了。
但是:
fisNew = new FileInputStream(newWorkbook);
oldWB = WorkbookFactory.create(new File(oldWorkbook));
newWB = WorkbookFactory.create(fisNew);
...
fileOut = new FileOutputStream(newWorkbook);
newWB.write(fileOut);
fileOut.close();
oldWB.close();
newWB.close();
应该可以。
顺便说一句:如果您使用的是 File
,那么您不应该对同一个文件使用 FileInputStream
。所以不要使用 fisOld
。
使用 File
而不是 FileInputStream
打开 Workbook
的另一个缺点是,在关闭 Workbook
因此隐式关闭底层文件系统(POIFSFileSystem
在 HSSF
的情况下和 ZipPackage
在 XSSF
的情况下)该文件获得更新的最后修改日期。没有对文件进行任何更改,但文件已被打开并新写入文件系统。这就是更新最后修改日期的原因。
2017 年 9 月 21 日编辑:使用 File
的缺点似乎比最初想象的要严重。 OPCPackage.close还将所有更改保存到底层 OPCPackage
中。因此,如果您从一个文件打开一个 XSSFWorkbook
,然后想使用 write(java.io.OutputStream stream)
将更改写入另一个文件,那么源文件也将在关闭 OPCPackage
时更改。仅当从 XSSFWorkbook
使用 write(java.io.OutputStream stream)
时才会出现此问题 POIXMLDocument.write被称为POIXMLDocumentPart.onSave其中“保存底层 OOXML 包中的更改。”。因此 OPCPackage
在关闭前更新了所有更改。
简短示例:
import org.apache.poi.ss.usermodel.*;
import java.io.File;
import java.io.FileOutputStream;
class ReadAndWriteExcelWorkbook {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new File("file.xlsx"));
Sheet sheet = workbook.getSheetAt(0);
Row row = sheet.getRow(0);
if (row == null) row = sheet.createRow(0);
Cell cell = row.getCell(0);
if (cell == null) cell = row.createCell(0);
cell.setCellValue("changed");
FileOutputStream out = new FileOutputStream("fileNew.xlsx");
workbook.write(out);
out.close();
workbook.close();
}
}
在这段代码之后,fileNew.xlsx
和 file.xlsx
都发生了变化。
关于java - Apache POI - FileInputStream 工作,文件对象失败(NullPointerException),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46146161/
我在Windows 10中使用一些简单的Powershell代码遇到了这个奇怪的问题,我认为这可能是我做错了,但我不是Powershell的天才。 我有这个: $ix = [System.Net.Dn
var urlsearch = "http://192.168.10.113:8080/collective-intellegence/StoreClicks?userid=" + userId +
我有一个非常奇怪的问题,过去两天一直让我抓狂。 我有一个我试图控制的串行设备(LS 100 光度计)。使用设置了正确参数的终端(白蚁),我可以发送命令(“MES”),然后是定界符(CR LF),然后我
我目前正试图让无需注册的 COM 使用 Excel 作为客户端,使用 .NET dll 作为服务器。目前,我只是试图让概念验证工作,但遇到了麻烦。 显然,当我使用 Excel 时,我不能简单地使用与可
我开发了简单的 REST API - https://github.com/pavelpetrcz/MandaysFigu - 我的问题是在本地主机上,WildFly 16 服务器的应用程序运行正常。
我遇到了奇怪的情况 - 从 Django shell 创建一些 Mongoengine 对象是成功的,但是从 Django View 创建相同的对象看起来成功,但 MongoDB 中没有出现任何数据。
我是 flask 的新手,只编写了一个相当简单的网络应用程序——没有数据库,只是一个航类搜索 API 的前端。一切正常,但为了提高我的技能,我正在尝试使用应用程序工厂和蓝图重构我的代码。让它与 pus
我的谷歌分析 JavaScript 事件在开发者控制台中运行得很好。 但是当从外部 js 文件包含在页面上时,它们根本不起作用。由于某种原因。 例如; 下面的内容将在包含在控制台中时运行。但当包含在单
这是一本名为“Node.js 8 the Right Way”的书中的任务。你可以在下面看到它: 这是我的解决方案: 'use strict'; const zmq = require('zeromq
我正在阅读文本行,并创建其独特单词的列表(在将它们小写之后)。我可以使它与 flatMap 一起工作,但不能使它与 map 的“子”流一起工作。 flatMap 看起来更简洁和“更好”,但为什么 di
我正在编写一些 PowerShell 脚本来进行一些构建自动化。我发现 here echo $? 根据前面的语句返回真或假。我刚刚发现 echo 是 Write-Output 的别名。 写主机 $?
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我将一个工作 View Controller 类从另一个项目复制到一个新项目中。我无法在新项目中加载 View 。在旧项目中我使用了presentModalViewController。在新版本中,我
我对 javascript 很陌生,所以很难看出我哪里出错了。由于某种原因,我的功能无法正常工作。任何帮助,将不胜感激。我尝试在外部 js 文件、头部/主体中使用它们,但似乎没有任何效果。错误要么出在
我正在尝试学习Flutter中的复选框。 问题是,当我想在Scaffold(body :)中使用复选框时,它正在工作。但我想在不同的地方使用它,例如ListView中的项目。 return Cente
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我有一个组合框,其中包含一个项目,比如“a”。我想调用该组合框的 Action 监听器,仅在手动选择项目“a”完成时才调用。我也尝试过 ItemStateChanged,但它的工作原理与 Action
你能看一下照片吗?现在,一步前我执行了 this.interrupt()。您可以看到 this.isInterrupted() 为 false。我仔细观察——“这个”没有改变。它具有相同的 ID (1
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我正在尝试在我的网站上设置一个联系表单,当有人点击发送时,就会运行一个作业,并在该作业中向所有管理员用户发送通知。不过,我在失败的工作表中不断收到此错误: Illuminate\Database\El
我是一名优秀的程序员,十分优秀!