2012-12-14 33 views
8

Próbuję przeczytać duże pliki CSV i TSV (Tab sepperated) z około 1000000 wierszami lub więcej. Teraz próbowałem odczytać linie TSV zawierające ~2500000 z , ale rzuca mi java.lang.NullPointerException. Działa z mniejszymi plikami TSV z liniami ~250000. Tak więc zastanawiałem się, czy są jakieś inne Libraries, które obsługują odczyt dużych plików CSV i TSV. Czy masz jakies pomysły?Dobry i skuteczny czytnik CSV/TSV dla języka Java

Każdy kto jest zainteresowany w moim kodu (I skrócić go, więc Try-Catch jest oczywiście nieważny):

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

Edit: Jest to metoda, gdzie skonstruować 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

Dlaczego nie czytasz tego samemu dzięki BufferedReader? –

+0

Właściwie chciałem mieć ładnie wykonane, często używane kodowanie i nie chcę wymyślać koła, właśnie dlatego wszyscy używają bibliotek, o których myślę. Ale jeśli nic nie działa, zrobię to. – Robin

+2

z tymi wieloma wierszami zajrzałbym do przetwarzania pliku w partiach: Czytaj n linii z pliku, przetwarzaj z csv, przeczytaj następną partię itp. – opi

Odpowiedz

5

I nie próbowałem tego, ale wcześniej zbadałem superCSV.

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

http://supercsv.sourceforge.net/

Sprawdź, czy działa dla Ciebie, 2,5 mln linii.

+0

Dziękuję, popatrzę na tę bibliotekę. – Robin

+0

Dziękuję. 'supercsv' obsługuje linie' 2 500 000' całkiem ładne. – Robin

+2

@Robin Jako programista w wersji CSV cieszę się, że mogę to usłyszeć, ale aby być uczciwym wobec opencsv, masz problemy z uruchamianiem (pamięcią), jeśli użyjesz 'read.readAll()' zamiast czytać każdą linię i coś z tym zrobić. Twoja metoda 'replaceBackslashes()' może również napotkać problemy podczas zapisywania całego pliku w pamięci. Czy twój NPE pojawił się podczas zamykania jednego ze swoich strumieni/czytników? –

1

Spróbuj przełączyć biblioteki zgodnie z sugestią Satish. Jeśli to nie pomoże, musisz podzielić cały plik na tokeny i przetworzyć je.

Myśląc, że CSV nie miał żadnych znaków ewakuacyjnych dla przecinkami

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

Następnie można je przetwarzać. Nie zapomnij o przycięciu tokena przed jego użyciem.

1

Nie wiem, czy to pytanie jest nadal aktywne, ale tutaj jest to, z którego korzystam z powodzeniem. Nadal może być konieczne wdrożenie większej liczby interfejsów, takich jak Stream lub Iterable, jednak:

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

Właściwie jestem całkiem zadowolony z SuperCSV, ale dziękuję za naturalną implementację – Robin

9

Nie używaj parsera CSV do analizowania danych wejściowych TSV. Przerywa, jeśli na przykład TSV ma pola ze znakiem cudzysłowu.

uniVocity-parsers zawiera parser TSV. Możesz bez problemu przeanalizować miliard wierszy.

Przykład analizować wejście TSV:

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

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

Jeśli wejście jest tak duża, że ​​nie mogą być przechowywane w pamięci, to zrobić:

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

Ujawnienie: Jestem autorem ta biblioteka. Jest open-source i bezpłatny (licencja Apache V2.0).

+1

Nie dokonałeś ustawień settings.setRowProcessor (rowProcessor); – userRaj

+1

Dzięki! zaktualizowałem moją odpowiedź. –