2012-02-01 11 views
10

Jaki jest prawdopodobnie najszybszy sposób czytania stosunkowo dużych plików za pomocą metod I/O Java? Moje obecne rozwiązanie wykorzystuje zapisanie BufferedInputStream do tablicy bajtów z przydzielonym 1024 bajtami. Każdy bufor jest następnie zapisywany w postaci ArrayList do późniejszego wykorzystania. Cały proces jest wywoływany przez osobny wątek (interfejs wywoływalny).Najszybszy sposób odczytywania stosunkowo dużych plików bajtowych w Javie

Niezbyt szybki.

ArrayList<byte[]> outputArr = new ArrayList<byte[]>();  
    try { 
     BufferedInputStream reader = new BufferedInputStream(new FileInputStream (dir+filename)); 

     byte[] buffer = new byte[LIMIT]; // == 1024 
      int i = 0; 
      while (reader.available() != 0) { 
       reader.read(buffer); 
       i++; 
       if (i <= LIMIT){ 
        outputArr.add(buffer); 
        i = 0; 
        buffer = null; 
        buffer = new byte[LIMIT]; 
       } 
       else continue;    
      } 

     System.out.println("FileReader-Elements: "+outputArr.size()+" w. "+buffer.length+" byte each."); 
+0

Zobacz biblioteki Apache Commons, aby uzyskać więcej opcji. Aby ustalić prędkość, spójrz na książkę o wydajności Java Performance O'Reilly. – therobyouknow

+5

Obecnie ignorujesz wartość zwracaną przez twoje wywołanie 'read()'. * Nie rób tego. * –

Odpowiedz

25

Chciałbym użyć pliku mapowanego pamięci, który jest wystarczająco szybki, aby wykonać w tym samym wątku.

final FileChannel channel = new FileInputStream(fileName).getChannel(); 
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); 

// when finished 
channel.close(); 

Zakłada się, że plik jest mniejszy niż 2 GB i zajmie 10 milisekund lub mniej.

+1

Krwawe piekło! Dlaczego do cholery to jest tak ekstremalnie szybko? Dzięki i tak działa idealnie. (edit: pobiera plik z pamięci, właśnie powiedział mi java doc. sprytny) –

+1

Jeśli potrzebujesz dostępu do więcej niż 2 GB, musisz użyć więcej niż jednego mapowania. –

3

Nie używaj available(): nie jest niezawodny. I nie ignoruj ​​wyniku metody read(): informuje, ile bajtów faktycznie przeczytano. A jeśli chcesz przeczytać wszystko w pamięci, użyj ByteArrayOutputStream zamiast używać List<byte[]>:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
int read; 
while ((read = reader.read(buffer)) >= 0) { 
    baos.write(buffer, 0, read); 
} 
byte[] everything = baos.toByteArray(); 

Myślę 1024 jest nieco małe jak rozmiar bufora. Chciałbym użyć większego bufora (coś takiego jak 16 KB lub 32 KB)

Zauważ, że Apache commons IO i Guava mają metody użytkowe, które robią to za Ciebie i zostały już zoptymalizowane.

1

Zobacz interfejs API Java NIO (Non-Blocking Input/Output). Ponadto może okazać się przydatny this question.

Nie mam dużego doświadczenia z IO, ale słyszałem, że NIO jest znacznie wydajniejszym sposobem obsługi dużych zbiorów danych.

Powiązane problemy