Saya sedang membangun prosesor XLSX yang mengubah XLSX menjadi file CSV. Karena filenya bisa menjadi cukup besar, saya menggunakan pendekatan berbasis peristiwa menggunakan XSSFSheetXMLHandler
Ini berfungsi dengan baik, tetapi file XLSX saya berisi angka panjang (13 digit) yang merupakan nomor identifikasi unik, bukan angka sebenarnya. Saat menjalankan kode saya di mesin Windows, kode tersebut mengekstrak angka dengan benar, tetapi saat dijalankan di mesin Linux, kode tersebut mengubahnya menjadi notasi E.
Misalnya: nilai sumbernya adalah 7401075293087. Di Windows, nilai ini diekstraksi dengan benar ke dalam CSV saya, tetapi di Linux nilainya muncul sebagai 7.40108E+12
Masalah dengan XSSFSheetXMLHandler adalah ia membaca XLSX di balik selimut dan kemudian menampilkan peristiwa yang ditangkap oleh SheetContentsHandler yang perlu Anda terapkan. Salah satu metode di SheetContentsHandler adalah metode sel dengan tanda tangan: sel (String cellReference, String formattedValue, XSSFComment comment)
Seperti yang Anda lihat, metode ini sudah menerima sel yang diformat (jadi dalam kasus saya ia menerima "7.40108E+12"). Logika lainnya terjadi secara tersembunyi.
Berdasarkan penyelidikan saya, saya yakin solusinya terletak pada mendefinisikan DataFormatter khusus yang secara khusus akan memperlakukan bilangan bulat 13 digit sebagai string, alih-alih memformatnya sebagai notasi E.
Sayangnya rencana saya tidak berjalan sesuai harapan dan saya tidak dapat menemukan bantuan online. Di bawah ini adalah ekstrak kode saya. Saya mencoba yang berikut ini dalam metode processSheet:
Locale locale = new Locale.Builder().setLanguage("en").setRegion("ZA").build();
DataFormatter formatter = new DataFormatter(locale);
Format format = new MessageFormat("{0,number,full}");
formatter.addFormat("#############", format);
Berikut ekstrak kode saya:
Bagian utama kode:
public void process(String Filename)throws IOException, OpenXML4JException, ParserConfigurationException, SAXException {
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
StylesTable styles = xssfReader.getStylesTable();
XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
while (iter.hasNext()) {
InputStream stream = iter.next();
String sheetName = iter.getSheetName();
outStream = new FileOutputStream(Filename);
logger.info(sheetName);
this.output = new PrintWriter(Filename);
processSheet(styles, strings, new SheetToCSV(), stream);
logger.info("Done with Sheet :"+sheetName);
output.flush();
stream.close();
outStream.close();
output.close();
++index;
}
}
public void processSheet(StylesTable styles,ReadOnlySharedStringsTable strings,SheetContentsHandler sheetHandler, InputStream sheetInputStream)
throws IOException, ParserConfigurationException, SAXException {
InputSource sheetSource = new InputSource(sheetInputStream);
try {
XMLReader sheetParser = SAXHelper.newXMLReader();
ContentHandler handler = new XSSFSheetXMLHandler(styles, null, strings, sheetHandler, formatter, false);
sheetParser.setContentHandler(handler);
sheetParser.parse(sheetSource);
} catch(ParserConfigurationException e) {
throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
}
}
Dan inilah penangan khusus:
private class SheetToCSV implements SheetContentsHandler {
private boolean firstCellOfRow = false;
private int currentRow = -1;
private int currentCol = -1;
private void outputMissingRows(int number) {
for (int i=0; i<number; i++) {
for (int j=0; j<minColumns; j++) {
output.append(',');
}
output.append('\n');
}
}
public void startRow(int rowNum) {
// If there were gaps, output the missing rows
outputMissingRows(rowNum-currentRow-1);
// Prepare for this row
firstCellOfRow = true;
currentRow = rowNum;
currentCol = -1;
}
public void endRow(int rowNum) {
// Ensure the minimum number of columns
for (int i=currentCol; i<minColumns; i++) {
output.append(',');
}
output.append('\n');
}
public void cell(String cellReference, String formattedValue,
XSSFComment comment) {
logger.info("CellRef :: Formatted Value :"+cellReference+" :: "+formattedValue);
if (firstCellOfRow) {
firstCellOfRow = false;
} else {
output.append(',');
}
// gracefully handle missing CellRef here in a similar way as XSSFCell does
if(cellReference == null) {
cellReference = new CellRangeAddress(currentRow, currentCol, currentCol, currentCol).formatAsString();
}
// Did we miss any cells?
int thisCol = (new CellReference(cellReference)).getCol();
int missedCols = thisCol - currentCol - 1;
for (int i=0; i<missedCols; i++) {
output.append(',');
}
currentCol = thisCol;
// Number or string?
try {
Double.parseDouble(formattedValue);
output.append(formattedValue);
} catch (NumberFormatException e) {
//formattedValue = formattedValue.replaceAll("\\t", "");
//formattedValue = formattedValue.replaceAll("\\n", "");
//formattedValue = formattedValue.trim();
output.append('"');
output.append(formattedValue.replace("\"", "\\\"").trim());
output.append('"');
}
}
public void headerFooter(String text, boolean isHeader, String tagName) {
// Skip, no headers or footers in CSV
}
@Override
public void ovveriddenFormat(String celRef, int formatIndex,
String formatedString) {
// TODO Auto-generated method stub
}
}