2012-09-28 4 views
4

거대한 csv 파일을 읽고 싶습니다. superCSV를 사용하여 일반적으로 파일을 구문 분석합니다. 이 특정 시나리오에서 파일은 거대하며 명백한 이유로 메모리 부족 문제가 항상 있습니다.superCSV를 사용하여 80GB의 큰 텍스트 파일을 읽으십시오.

초기 아이디어는 파일을 청크로 읽는 것이지만 파일을 청크 할 때 첫 번째 청크 만 헤더 값을 갖고 CSV 빈에로드되기 때문에 이것이 superCSV와 작동하는지 잘 모릅니다. 다른 청크에는 헤더 값이 없으므로 예외가 발생할 수 있다고 생각합니다. 그래서

a) 내 생각 프로세스가 올바른지 궁금합니다.
b) 다른 방법으로이 문제에 접근하고 있습니까?

그래서 내 주요 질문은

합니까 superCSV 큰 CSV 파일을 처리 할 수있는 능력을 가지고 있고이 superCSV이의 BufferedReader를 통해 문서를 읽는 것을 볼 수있다. 하지만 버퍼의 크기는 무엇인지 알지 못합니다. 요구 사항에 따라 버퍼를 변경할 수 있습니까?

@ Gilbert Le Blanc 나는 제안대로 작은 덩어리로 분할하려고했지만 거대한 파일을 작은 덩어리로 분해하는 데 오랜 시간이 걸립니다. 여기에 제가 작성한 코드가 있습니다.

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileReader; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.LineNumberReader; 

public class TestFileSplit { 

public static void main(String[] args) { 

    LineNumberReader lnr = null; 
    try { 
     //RandomAccessFile input = new RandomAccessFile("", "r"); 
     File file = new File("C:\\Blah\\largetextfile.txt"); 
     lnr = new LineNumberReader(new FileReader(file), 1024); 
     String line = ""; 
     String header = null; 
     int noOfLines = 100000; 
     int i = 1; 
     boolean chunkedFiles = new File("C:\\Blah\\chunks").mkdir(); 
     if(chunkedFiles){ 
      while((line = lnr.readLine()) != null) { 
       if(lnr.getLineNumber() == 1) { 
        header = line; 
        continue; 
       } 
       else { 
        // a new chunk file is created for every 100000 records 
        if((lnr.getLineNumber()%noOfLines)==0){ 
         i = i+1; 
        } 

        File chunkedFile = new File("C:\\Blah\\chunks\\" + file.getName().substring(0,file.getName().indexOf(".")) + "_" + i + ".txt"); 

        // if the file does not exist create it and add the header as the first row 
        if (!chunkedFile.exists()) { 
         file.createNewFile(); 
         FileWriter fw = new FileWriter(chunkedFile.getAbsoluteFile(), true); 
         BufferedWriter bw = new BufferedWriter(fw); 
         bw.write(header); 
         bw.newLine(); 
         bw.close(); 
         fw.close(); 
        } 

        FileWriter fw = new FileWriter(chunkedFile.getAbsoluteFile(), true); 
        BufferedWriter bw = new BufferedWriter(fw); 
        bw.write(line); 
        bw.newLine(); 
        bw.close(); 
        fw.close(); 
       } 
      } 
     } 
     lnr.close(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
    } 
} 
} 
+0

첫 번째 청크에 헤더 값 행을 만듭니다. 그런 다음 첫 번째 청크를 다른 많은 청크와 연결하여 한 번에 하나의 청크를 처리하여 충분히 큰 파일을 작게 만드십시오. –

+0

나는 무엇이 이것을 일으키는 지 궁금하다. 일단 읽은 콩으로 무엇을하고 있니? 목록에 추가하는 경우 메모리 부족 현상이 발생할 가능성이 큽니다. 독자가 읽을 때마다 각 bean을 처리하도록 응용 프로그램 구조를 변경하거나 작은 그룹으로 처리 할 수 ​​있습니까? –

답변

1

나는 무엇이 문제인지 잘 모르겠습니다. 한 번에 한 행을 콩으로 읽는 것은 대략 일정한 메모리 소비를 필요로합니다. 한 번에 모든 읽기 객체를 저장하면 예를 들어 메모리가 부족합니다. 하지만이 슈퍼 CSV의 잘못은 무엇입니까?

+0

예, 문제가되지 않습니다. csv에서 super csv를 통해 읽는 방법은 파일 판독기를 사용하는 것입니다. 파일이 정말 커 졌으니 나는 메모리 부족 문제에 직면 해있다. 나는 그것이 supercsv의 잘못이라고 말하지 않는다. 나는 더 일찍 명확하지 않았을지도 모른다. 다음은 재구성 된 질문입니다. 내가 180 기가 바이트의 csv 파일을 가지고 있고 내가 그것을로드하려고 SuperCSV에 피드하려고한다면 나는 꽤 예외적이다. 그 때문에 길버트 sais 내가 작은 파일에 그것을 덩어리려고하고 다음을 읽고 노력하고있어,하지만 정확히 어떻게 2GB의 파일을 덩어리 어떻게 해야하는지에 대해 어떻게 가야할지 모르겠다 – user1707141

+0

파일을 나눌 필요가 없습니다 작은 덩어리로. 여기 내가하는 일이있다. 먼저 헤더 행을 읽고 String []에 저장합니다. 그런 다음 X 바이트 또는 X 줄 파일을 한 번에 읽습니다. 여기서 X는 메모리 제약 사항이있는 이상적인 크기입니다. 그런 다음 String으로 표시되는 각 청크 X에 대해 CsvReader 생성자에 전달하는 StringReader를 만듭니다. 그런 다음 CsvReader의 read() 메서드가 null을 반환 할 때까지 구문 분석을 계속합니다. 그 후, 파일에서 다음 X를 읽고, 끝날 때까지 위에서 계속하십시오. – Aquarelle

2

파서 자바 클래스 자체에서 헤더를 정의 할 수 있습니다. 그렇게하면 CSV 파일에 헤더 행이 필요하지 않습니다.

// only map the first 3 columns - setting header elements to null means those columns are ignored 
final String[] header = new String[] { "customerNo", "firstName", "lastName", null, null, null, null, null, null, null }; 
beanReader.read(CustomerBean.class, header) 

또는

또한 SuperCSV API를의 도저 확장을 사용할 수 있습니다.