2012-12-14 34 views
8

Tôi đang cố gắng đọc các tệp lớn CSVTSV (Tab sepperated) với khoảng 1000000 hàng trở lên. Bây giờ tôi đã cố gắng đọc một số TSV chứa ~2500000 dòng với opencsv, nhưng nó ném cho tôi một java.lang.NullPointerException. Nó hoạt động với các tệp TSV nhỏ hơn với các dòng ~250000. Vì vậy, tôi đã tự hỏi nếu có bất kỳ Libraries khác hỗ trợ việc đọc các tệp CSVTSV lớn. Bạn có bất cứ ý tưởng?Đầu đọc CSV/TSV hiệu quả và tốt cho Java

Mọi người ai quan tâm đến Mã của tôi (tôi rút ngắn nó, vì vậy Try-Catch rõ ràng là không hợp lệ):

InputStreamReader in = null; 
CSVReader reader = null; 
try { 
    in = this.replaceBackSlashes(); 
    reader = new CSVReader(in, this.seperator, '\"', this.offset); 
    ret = reader.readAll(); 
} finally { 
    try { 
     reader.close(); 
    } 
} 

Chỉnh sửa: Đây là phương pháp mà tôi xây dựng InputStreamReader:

private InputStreamReader replaceBackSlashes() throws Exception { 
     FileInputStream fis = null; 
     Scanner in = null; 
     try { 
      fis = new FileInputStream(this.csvFile); 
      in = new Scanner(fis, this.encoding); 
      ByteArrayOutputStream out = new ByteArrayOutputStream(); 

      while (in.hasNext()) { 
       String nextLine = in.nextLine().replace("\\", "/"); 
       // nextLine = nextLine.replaceAll(" ", ""); 
       nextLine = nextLine.replaceAll("'", ""); 
       out.write(nextLine.getBytes()); 
       out.write("\n".getBytes()); 
      } 

      return new InputStreamReader(new ByteArrayInputStream(out.toByteArray())); 
     } catch (Exception e) { 
      in.close(); 
      fis.close(); 
      this.logger.error("Problem at replaceBackSlashes", e); 
     } 
     throw new Exception(); 
    } 
+2

Tại sao bạn không tự đọc nó nhờ một BufferedReader? –

+0

Thực sự tôi muốn có được chế tác độc đáo, Mã được sử dụng phổ biến và tôi không muốn phát minh lại bánh xe, thực ra đó là lý do mọi người sử dụng libs tôi nghĩ. Nhưng nếu không có gì làm việc, tôi sẽ làm như vậy. – Robin

+2

với nhiều hàng tôi sẽ xem xét xử lý tệp theo lô: Đọc n dòng từ tệp, xử lý bằng csv, đọc hàng loạt tiếp theo, v.v. – opi

Trả lời

5

tôi đã không thử nó, nhưng tôi đã điều tra superCSV trước đó.

http://sourceforge.net/projects/supercsv/

http://supercsv.sourceforge.net/

Kiểm tra nếu mà làm việc cho bạn, 2,5 triệu dòng.

+0

Cảm ơn bạn Tôi sẽ có một cái nhìn tại lib này. – Robin

+0

Cảm ơn bạn. 'supercsv' xử lý các dòng' 2 500 000' khá đẹp. – Robin

+2

@Robin Là nhà phát triển siêu CSV Tôi rất vui khi nghe điều này, mặc dù công bằng với opencsv, bạn bị ràng buộc gặp phải các vấn đề (bộ nhớ) nếu bạn sử dụng 'reader.readAll()' thay vì đọc từng dòng và làm gì đó với nó. Phương thức 'replaceBackslashes()' của bạn cũng có thể chạy vào các vấn đề khi bạn đang viết toàn bộ tệp vào bộ nhớ. NPE của bạn có xảy ra khi đóng một trong các luồng/trình đọc của bạn không? –

1

Thử chuyển đổi thư viện theo đề xuất của Satish. Nếu điều đó không hiệu quả, bạn phải chia toàn bộ tập tin thành các thẻ và xử lý chúng.

Nghĩ rằng CSV của bạn không có bất kỳ ký tự thoát cho dấu phẩy

// r is the BufferedReader pointed at your file 
String line; 
StringBuilder file = new StringBuilder(); 
// load each line and append it to file. 
while ((line=r.readLine())!=null){ 
    file.append(line); 
} 
// Make them to an array 
String[] tokens = file.toString().split(","); 

Sau đó, bạn có thể xử lý nó. Đừng quên cắt mã thông báo trước khi sử dụng nó.

1

Tôi không biết câu hỏi đó vẫn hoạt động nhưng đây là câu hỏi tôi sử dụng thành công. Tuy nhiên, có thể phải triển khai nhiều giao diện hơn như Luồng hoặc Lặp lại, tuy nhiên:

import java.io.Closeable; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.Scanner; 

/** Reader for the tab separated values format (a basic table format without escapings or anything where the rows are separated by tabulators).**/ 
public class TSVReader implements Closeable 
{ 
    final Scanner in; 
    String peekLine = null; 

    public TSVReader(InputStream stream) throws FileNotFoundException 
    { 
     in = new Scanner(stream); 
    } 

    /**Constructs a new TSVReader which produces values scanned from the specified input stream.*/ 
    public TSVReader(File f) throws FileNotFoundException {in = new Scanner(f);} 

    public boolean hasNextTokens() 
    { 
     if(peekLine!=null) return true; 
     if(!in.hasNextLine()) {return false;} 
     String line = in.nextLine().trim(); 
     if(line.isEmpty()) {return hasNextTokens();} 
     this.peekLine = line;  
     return true;   
    } 

    public String[] nextTokens() 
    { 
     if(!hasNextTokens()) return null;  
     String[] tokens = peekLine.split("[\\s\t]+"); 
//  System.out.println(Arrays.toString(tokens)); 
     peekLine=null;  
     return tokens; 
    } 

    @Override public void close() throws IOException {in.close();} 
} 
+0

Thực ra tôi khá hài lòng với SuperCSV. Tuy nhiên, cảm ơn bạn đã thực hiện tự nhiên – Robin

9

Không sử dụng trình phân tích cú pháp CSV để phân tích đầu vào TSV. Nó sẽ phá vỡ nếu TSV có các trường với một ký tự trích dẫn, ví dụ.

uniVocity-parsers đi kèm với trình phân tích cú pháp TSV. Bạn có thể phân tích cú pháp một tỷ hàng mà không gặp vấn đề gì.

Ví dụ để phân tích một đầu vào TSV:

TsvParserSettings settings = new TsvParserSettings(); 
TsvParser parser = new TsvParser(settings); 

// parses all rows in one go. 
List<String[]> allRows = parser.parseAll(new FileReader(yourFile)); 

Nếu đầu vào của bạn là quá lớn nó không thể được lưu giữ trong bộ nhớ, làm điều này:

TsvParserSettings settings = new TsvParserSettings(); 

// all rows parsed from your input will be sent to this processor 
ObjectRowProcessor rowProcessor = new ObjectRowProcessor() { 
    @Override 
    public void rowProcessed(Object[] row, ParsingContext context) { 
     //here is the row. Let's just print it. 
     System.out.println(Arrays.toString(row)); 
    } 
}; 
// the ObjectRowProcessor supports conversions from String to whatever you need: 
// converts values in columns 2 and 5 to BigDecimal 
rowProcessor.convertIndexes(Conversions.toBigDecimal()).set(2, 5); 

// converts the values in columns "Description" and "Model". Applies trim and to lowercase to the values in these columns. 
rowProcessor.convertFields(Conversions.trim(), Conversions.toLowerCase()).set("Description", "Model"); 

//configures to use the RowProcessor 
settings.setRowProcessor(rowProcessor); 

TsvParser parser = new TsvParser(settings); 
//parses everything. All rows will be pumped into your RowProcessor. 
parser.parse(new FileReader(yourFile)); 

Tiết lộ: Tôi là tác giả của thư viện này. Đó là mã nguồn mở và miễn phí (giấy phép Apache V2.0).

+1

Bạn chưa thực hiện settings.setRowProcessor (rowProcessor); – userRaj

+1

Cảm ơn! đã cập nhật câu trả lời của tôi. –

Các vấn đề liên quan