我正在使用下面的代码将.csv文件转换为. xlsx。它工作正常,但客户希望得到“智能Excel表”(与过滤器等,格式为表在Microsoft Excel)。
使用Apache NiFI和Groovy:
@Grab("org.apache.poi:poi:3.16")
@Grab("org.apache.poi:poi-ooxml:3.16")
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.*;
import org.apache.commons.io.IOUtils
import java.nio.charset.StandardCharsets
def flowFile = session.get()
if(!flowFile)
return
flowFile = session.write(flowFile, { inputStream, outputStream ->
try {
SXSSFWorkbook workBook = new SXSSFWorkbook();
workBook.setCompressTempFiles(true);
SXSSFSheet sheet = workBook.createSheet("Sheet");
sheet.setRandomAccessWindowSize(1000);
String currentLine = null;
int RowNum = 0;
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
while ((currentLine = br.readLine()) != null) {
String[] str = currentLine.split(",");
Row currentRow = sheet.createRow(RowNum);
for(int i=0;i<str.length;i++){
currentRow.createCell(i).setCellValue(str[i]);
}
RowNum++;
if (RowNum % 1000 == 0) {
println RowNum;
}
}
workBook.write(outputStream);
fileOutputStream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
} as StreamCallback)
session.transfer(flowFile, REL_SUCCESS)
我的版本如下所示:
客户希望获得如下SMTH:
我怎样才能做到这一点?
2条答案
按热度按时间4jb9z9bj1#
首先:将CSV文件逐行读取为纯文本文件,并按分隔符拆分,容易出错。此方法未考虑CSV规则。例如:值可以用引号括起来。逗号和下一个值之间可能有空格,那么它就不应该是值的一部分。依此类推。CSV文件应该用专门为它设计的库来读取。例如opencsv。
在Excel中创建表格是Apache POI的一部分。有XSSFSheet.createTable。不幸的是没有
SXSSFSheet.createTable
。而且由于CSV的大小,您需要流版本SXSSF
,对吗?要克服这个问题,可以从
SXSSFWorkbook
中取出底层XSSFWorkbook
,在那里创建XSSFTable
。在流入SXSSFSheet
时,基础XSSFSheet
不包含任何数据。这是XSSFSheet.createTable(AreaReference)
在AreaReference
的第一行中找不到任何列名并创建具有列名"列1"、"列2"、"列3"、...的表的原因。这些与工作表的实际内容不匹配。这就是为什么我们需要在表格创建后更新标题的原因。完整示例:
cities.csv
的内容在此为文本:在文本编辑器中复制/粘贴。然后另存为
cities.csv
。您可以从此处下载其他CSV文件进行测试:https://www.stats.govt.nz/large-datasets/csv-files-for-download/.
另一个问题是使用
Cell.setCellValue
时总是使用字符串值,而Excel在字符串和数字单元格值之间存在差异。但这是使用CSV时的一个众所周知的问题。用户需要一个额外的定义文件来显示CSV列的数据类型。c8ib6hqw2#
您可以参考以下方法:
对于颜色,您可能必须使用单元格样式。
所有这些都有文档记录,也许从this开始。