ฉันกำลังสร้างโปรเซสเซอร์ XLSX ที่แปลง XLSX เป็นไฟล์ CSV เนื่องจากไฟล์อาจมีขนาดใหญ่มาก ฉันจึงใช้แนวทางตามเหตุการณ์โดยใช้ XSSFSheetXMLHandler
วิธีนี้ใช้ได้ผลดีอย่างสมบูรณ์ แต่ไฟล์ XLSX ของฉันมีตัวเลขยาว (13 หลัก) ซึ่งเป็นหมายเลขประจำตัวที่ไม่ซ้ำกัน ไม่ใช่ตัวเลขจริง เมื่อรันโค้ดของฉันบนเครื่อง Windows มันจะแยกตัวเลขอย่างถูกต้อง แต่เมื่อรันบนเครื่อง Linux มันจะแปลงเป็นสัญลักษณ์ E
ตัวอย่างเช่น: ค่าแหล่งที่มาคือ 7401075293087 บน windows ค่านี้จะถูกแตกออกเป็น CSV ของฉันอย่างถูกต้อง แต่บน Linux ค่าจะเป็น 7.40108E+12
ปัญหาของ XSSFSheetXMLHandler คือมันจะอ่าน XLSX ใต้หน้าปก จากนั้นจึงโยนเหตุการณ์ที่ SheetContentsHandler จับได้ซึ่งคุณต้องนำไปใช้ วิธีหนึ่งใน SheetContentsHandler คือวิธีการของเซลล์ที่มีลายเซ็นต์: cell(String cellReference, String formattedValue, XSSFComment comment)
อย่างที่คุณเห็น วิธีนี้ได้รับเซลล์ที่จัดรูปแบบแล้ว (ดังนั้นในกรณีของฉันจะได้รับ "7.40108E+12") ตรรกะที่เหลือทั้งหมดเกิดขึ้นภายใต้ผ้าคลุม
จากการตรวจสอบของฉัน ฉันเชื่อว่าวิธีแก้ปัญหาอยู่ที่การกำหนด DataFormatter แบบกำหนดเองซึ่งจะถือว่าจำนวนเต็ม 13 หลักเป็นสตริงโดยเฉพาะ แทนที่จะจัดรูปแบบเป็นสัญลักษณ์ E
น่าเสียดายที่แผนของฉันไม่ได้ผลตามที่คาดไว้ และฉันไม่พบความช่วยเหลือทางออนไลน์ ด้านล่างนี้เป็นสารสกัดจากรหัสของฉัน ฉันลองสิ่งต่อไปนี้ในวิธี 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);
นี่คือสารสกัดจากรหัสของฉัน:
เนื้อหาหลักของรหัส:
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());
}
}
และนี่คือตัวจัดการแบบกำหนดเอง:
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
}
}