2014-09-18 1 views
1

XLSX를 Java를 사용하여 CSV 파일로 변환하는 방법을 많이 발견했습니다. 모든 솔루션에는 XSSFWorkbook이 사용됩니다. 내가 직면 한 문제는 스트림에 너무 많은 데이터가있는 것 같습니다. 나는 이유를 모르겠다. 파일은 단지 4MB이다.XLSX에서 CSV로 메모리 부족 오류

CODE : 오류가 나는 데이터 (StringBuffer를) 뭔가를 추가하고 스위치 문에서 줄을 가리키는하지만 문제가 될해서는 안 내가 널링하고

// 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(); 

.

+1

효율적이지 않을 수도있는'StringBuffer'에서 물건을 채우고 있습니다. 어쨌든 그것을 왜 메모리에 저장해야합니까? 한 줄을 만들고 파일에 쓰고 계속 진행하면됩니다 (아마도'BufferedWriter'를 사용하기를 원할 것입니다.) 또한 String을 만들고 그것을 메모리 풋 프린트와 중복되는'byte []'로 변환하는 이유는 무엇입니까? 당신의 JVM과 GC의 속도는 많은 추가적인 객체를 얻습니다. 한 가지 시도는 한계를 낮추는 것입니다, 그리고 새로운'StringBuffer'를 생성하는 대신 그것을 비우고 재사용하는 것입니다 .'StringBuffer' 대신 –

+0

그래, 그냥 setLength (0)을 사용하기 전에 문제가 거기에 없었지만 fileInputStream 중이었습니다 –

+1

큰 개체가 주변에 머물러있어 재사용 성이 좋을 수도 있습니다. 읽는 동안 그것이 발생하는 것을 의미하지 않습니다. 당신의 메모리가 가득 차고 큰'StringBuffer'가 처음 수정 될 것입니다. 또 다른 메모는 당신이'StringBuffer'를 사용하고 있지만 아직도 문자열 concat을 사용하여 추가하고 있습니다. 문자열. 나는' + ";" "를 case 문 다음에 추가하고 case 문 다음에'data.append (';')'를 추가하십시오. concat에 대한 추가 String 생성을 저장합니다. –

답변

0

이제 쓰기 전용이므로 SXSSFWorkbook을 사용하지 못할 수도 있지만 SAX-based API을 사용하여 프로그램을 스트리밍 스타일로 변환 할 수 있습니다. 편집 : 시도해 볼 수도있는 또 다른 사항은 FileStream 기반의 XSSFWorkbook을 만드는 것입니다. File 기반 코드의 메모리 사용량이 적어집니다.

(첫 번째 시도했다 : 당신이 데이터를 순차적으로 읽기 때문에 는 SXSSFWorkbook 클래스는 당신이 필요로하는 단지 일이 될 것이다.)

+0

SXSSFWorkbook은 쓰기 전용입니다. http://stackoverflow.com/questions/12513981/reading-data-from-xlsx-with-apache-pois-sxssfsheet –

+0

어쨌든 고마워요. –

0

XLSX 형식은 내용 XML과 공유 문자열 XML을 단지 우편 번호입니다. 따라서 4MB 압축 된, 압축되지 않은 매우 큰 수 있습니다.

zip 파일 시스템을 사용하면 공유 문자열을 메모리에로드 한 다음 내용 xml을 순차적으로 읽고 즉시 출력 할 수 있습니다.

두 개의 내부 파일이 관련되어 있으므로 java의 zip 파일 시스템을 사용할 수 있습니다. 지루하고 어렵지 않습니다.