【问题标题】:XLSX to CSV out of memory errorXLSX 到 CSV 内存不足错误
【发布时间】:2014-11-12 18:40:17
【问题描述】:

我找到了很多如何使用 Java 将 XLSX 转换为 CSV 文件的解决方案,所有解决方案都使用:XSSFWorkbook。我面临的问题是流可能包含太多数据。我只是不明白为什么,文件只有 4mb。

代码:

// For storing data into CSV files
    StringBuffer data = new StringBuffer();
    try {
        FileOutputStream fos = new FileOutputStream(outputFile);
        System.out.println("Getting input stream.");
        // Get the workbook object for XLS file
        XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(inputFile));
        System.out.println(" - Done");
        // Get first sheet from the workbook
        XSSFSheet sheet = workbook.getSheetAt(0);
        Cell cell;
        Row row;

        // Iterate through each rows from first sheet
        Iterator<Row> rowIterator = sheet.iterator();
        System.out.println(" - Reading xlsx rows.");
        while (rowIterator.hasNext()) {
            i++;

            row = rowIterator.next();
            // For each row, iterate through each columns
            Iterator<Cell> cellIterator = row.cellIterator();
            while (cellIterator.hasNext()) {
                cell = cellIterator.next();

                switch (cell.getCellType()) {
                case Cell.CELL_TYPE_BOOLEAN:
                    data.append(cell.getBooleanCellValue() + ";");
                    break;

                case Cell.CELL_TYPE_NUMERIC:
                    data.append(cell.getNumericCellValue() + ";");
                    break;

                case Cell.CELL_TYPE_STRING:
                    data.append(cell.getStringCellValue() + ";");
                    break;

                case Cell.CELL_TYPE_BLANK:
                    data.append("" + ";");
                    break;

                default:
                    data.append(cell + ";");
                }

            }
            data.append('\n');
            int limit = 10000;
            if ((i % limit) == 0) {
                System.out.println(" - Writing " + limit + " data.");
                fos.write(data.toString().getBytes());
                fos.flush();
                data = null;
                data = new StringBuffer();
                System.out.println(" - Data written.");
            }
        }

        fos.write(data.toString().getBytes());
        fos.flush();
        fos.close();

错误指向 switch 语句中的行,我在其中向数据 (StringBuffer) 附加了一些内容,但我将其置空,所以它不应该成为问题。

【问题讨论】:

  • 你在StringBuffer 里塞东西,这可能效率不高。为什么还要将它存储在内存中?只需创建一行,将其写入文件并继续(您可能想使用BufferedWriter。另外,为什么要创建一个字符串并将其转换为byte[],下一个复制内存占用。取决于速度在你的 JVM 和 GC 中,你会得到很多额外的对象。尝试和开始的一件事是降低你的限制,而不是构造一个新的 StringBuffer 只是清空并重用它。而不是 StringBUffer 我建议使用StringBuilder
  • 是的,在我使用 setLength(0) 之前,问题不存在,它是在 fileInputStream 期间。
  • 大型对象可能会徘徊,因此重用可能会更好。它在阅读时发生的事实并不意味着它是因为阅读。你的记忆正在填满,大的StringBuffer 将是我的第一个修复。另一个注意事项是您正在使用 StringBuffer 但仍在使用 String concat 添加字符串。我建议从您的案例陈述中删除+ ";",并在案例陈述之后添加data.append(';')。保存为 concat 创建额外的字符串。

标签: java excel csv xlsx xssf


【解决方案1】:

现在您可能无法使用 SXSSFWorkbook(因为它是只写的),但您可以使用 SAX-based API 将您的程序转换为流式传输样式。编辑:您可能想尝试的另一件事是从 File 而不是 InputStream 创建 XSSFWorkbook(我记得在某处读到基于文件的代码需要更少的内存)。

(第一次尝试是: 由于您是按顺序读取数据,因此 SXSSFWorkbook 类应该正是您所需要的。)

【讨论】:

【解决方案2】:

xlsx 格式只是一个包含内容 xml 和共享字符串 xml 的 zip。因此 4 MB 压缩后,未压缩可能非常大。

使用 zip 文件系统,您可以将共享字符串加载到内存中,然后顺序读取内容 xml,立即输出。

对于两个内部文件,你可以使用 java 的 zip 文件系统。乏味但不难。

【讨论】:

    【解决方案3】:

    试试这个代码,这个代码对我来说非常有用,我希望它也对你有用。

    package com.converting;
    
    import java.io.FileInputStream;
    import java.io.*;
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import com.opencsv.CSVWriter;
    import java.util.Iterator;
    import java.io.FileWriter;
    
    public class XlsxtoCSV {
    
            public static void main(String[] args) throws Exception{
                 FileInputStream input_document = new FileInputStream(new File("/home/blackpearl/Downloads/aa.xlsx"));
                 XSSFWorkbook my_xls_workbook = new XSSFWorkbook(input_document); 
                 XSSFSheet  my_worksheet = my_xls_workbook.getSheetAt(0); 
    
                 Iterator<Row> rowIterator = my_worksheet.iterator();
                 FileWriter my_csv=new FileWriter("/home/blackpearl/Downloads/Newaa.csv");
                 CSVWriter my_csv_output=new CSVWriter(my_csv); 
                 while(rowIterator.hasNext()) {
                         Row row = rowIterator.next(); 
                         int i=0;//String array
                         String[] csvdata = new String[20];
                         Iterator<Cell> cellIterator = row.cellIterator();
                                 while(cellIterator.hasNext()) {
                                         Cell cell = cellIterator.next(); //Fetch CELL
                                         switch(cell.getCellType()) { //Identify CELL type
                                         case Cell.CELL_TYPE_STRING:
                                                 csvdata[i]= cell.getStringCellValue();                                              
                                                 break;
                                         }
                                         i=i+1;
                                 }
                 my_csv_output.writeNext(csvdata);
                 }
                 System.out.println("file imported");
                 my_csv_output.close(); //close the CSV file
                 input_document.close(); //close xlsx file
         }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      相关资源
      最近更新 更多