2015-10-18 16 views
5

Więc wiesz, że możesz używać AsynchronousFileChannel przeczytać cały plik do sznurka:Jak korzystać AsynchronousFileChannel czytać do StringBuffer skutecznie

AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(filePath, StandardOpenOption.READ); 
      long len = fileChannel.size(); 

      ReadAttachment readAttachment = new ReadAttachment(); 
      readAttachment.byteBuffer = ByteBuffer.allocate((int) len); 
      readAttachment.asynchronousChannel = fileChannel; 

      CompletionHandler<Integer, ReadAttachment> completionHandler = new CompletionHandler<Integer, ReadAttachment>() { 

       @Override 
       public void completed(Integer result, ReadAttachment attachment) { 

        String content = new String(attachment.byteBuffer.array()); 
        try { 
         attachment.asynchronousChannel.close(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
        completeCallback.accept(content); 
       } 

       @Override 
       public void failed(Throwable exc, ReadAttachment attachment) { 
        exc.printStackTrace(); 
        exceptionError(errorCallback, completeCallback, String.format("error while reading file [%s]: %s", path, exc.getMessage())); 
       } 
      }; 

      fileChannel.read(
        readAttachment.byteBuffer, 
        0, 
        readAttachment, 
        completionHandler); 

Załóżmy, że teraz, nie chcę przeznaczyć cały ByteBuffer , ale czytuj linia po linii. Mógłbym użyć ByteBuffer o stałej szerokości i ciągle przywoływać read wiele razy, zawsze kopiując i dołączając do StringBuffer, dopóki nie dostanę nowej linii ... Moje jedyne zmartwienie to: ponieważ kodowanie pliku, który czytam może być wielobajtowy na znak (coś UTF), może się zdarzyć, że przeczytane bajty kończą się niekompletną postacią. Jak mogę się upewnić, że konwertuję właściwe bajty na ciągi i nie zepsuję kodowania?

AKTUALIZACJA: odpowiedź jest w komentarzu wybranej odpowiedzi, ale w zasadzie wskazuje na CharsetDecoder.

+3

Nie stosować asynchroniczne I/O czytać wiersze. Po prostu nie nadaje się. Możesz przeczytać miliony linii na sekundę za pomocą 'BufferedReader.readLine().' – EJP

+0

Potrzebuję operacji bez blokowania! – gotch4

+0

Dlaczego więc używasz asynchronicznych I/O? To nie jest blokowanie. Jest to trzeci paradygmat, po blokowaniu i bez blokowania. Ale dlaczego myślisz, że nie możesz w pierwszej kolejności korzystać z blokujących wejść/wyjść? – EJP

Odpowiedz

1

Jeśli masz czysty separator ASCII, który masz w swoim przypadku (\ n), nie będziesz musiał przejmować się niekompletnym łańcuchem, ponieważ ten znak jest mapowany na pojedynczy bajt (i na odwrót).

Po prostu wyszukaj bajt "\ n" w danych wejściowych i przeczytaj i przekonwertuj wszystko przed wprowadzeniem do łańcucha znaków. Loop, dopóki nie zostaną znalezione nowe linie. Następnie skompaktuj bufor i użyj go ponownie do następnego odczytu. Jeśli nie znajdziesz nowej linii, musisz przydzielić większy bufor, skopiować zawartość starego i dopiero potem wywołać odczyt ponownie.

EDYCJA: Jak wspomniano w komentarzu, można w dowolnym momencie przekazać bajt BuffBuffer do CharsetDecoder i przetłumaczyć go na CharBuffer (następnie dołączyć do StringBuilder lub cokolwiek innego jest preferowanym rozwiązaniem).

+0

W ten sposób muszę przechowywać całą linię jako bufor bajtów ... Niech na chwilę zapomnę, że mam do czynienia z liniami ... I że mój bufor jest ograniczony (linie mogą być bardzo długie). Jak byśmy zrobili? – gotch4

+1

Możesz użyć http://docs.oracle.com/javase/7/docs/api/java/nio/charset/CharsetDecoder.html#decode(java.nio.ByteBuffer,%20java.nio.CharBuffer,%20boolean) przekształcić dane wejściowe w locie. Nadal będziesz musiał zarządzać buforem, ponieważ może on zawierać pozostałe znaki między odczytami. –

+0

Idealnie! Dzięki, rozważ zaktualizowanie odpowiedzi ponownie, – gotch4

0

Spróbuj skanera:

Scanner sc = new Scanner(FileChannel.open(filePath, StandardOpenOption.READ)); 
    String line = sc.readLine(); 

FileChannel jest InterruptibleChannel

+0

, nie potrzebuję przerywania, muszę uruchomić odczyt i wywołanie zwrotne później ... – gotch4

Powiązane problemy