2015-10-18 12 views
5

Così si sa che si può utilizzare AsynchronousFileChannel per leggere un intero file in una stringa:Come utilizzare AsynchronousFileChannel da leggere per uno StringBuffer efficiente

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

Supponiamo che ora, non voglio di destinare un intero ByteBuffer , ma leggi riga per riga. Potrei usare uno ByteBuffer di larghezza fissa e continuare a richiamare read molte volte, copiare sempre e accodare a un StringBuffer fino a quando non arrivo a una nuova riga ... La mia unica preoccupazione è: perché la codifica del file che sto leggendo potrebbe essere multi byte per carattere (qualcosa di UTF), potrebbe accadere che i byte letti finiscano con un carattere incompleto. Come posso essere sicuro di convertire i byte giusti in stringhe e non di incasinare la codifica?

UPDATE: risposta è nel commento della risposta selezionata, ma in pratica punta a CharsetDecoder.

+3

Non utilizzare async I/O per leggere le linee. Non è adatto. Puoi leggere milioni di righe al secondo con 'BufferedReader.readLine().' – EJP

+0

Ho bisogno di operazioni di blocco! – gotch4

+0

Allora perché stai usando I/O asincrono? Questo non è non-bloccante. È un terzo paradigma, dopo aver bloccato e non bloccato. Ma perché pensi che non puoi usare l'I/O di blocco in primo luogo? – EJP

risposta

1

Se si dispone del separatore ASCII chiaro che si ha nel caso (\ n), non sarà necessario preoccuparsi della stringa incompleta in quanto questo carattere viene mappato su singlebyte (e viceversa).

Quindi basta cercare '\ n' byte nel proprio input e leggere e convertire qualsiasi cosa prima in String. Fai clic su finché non vengono trovate nuove righe. Quindi compattare il buffer e riutilizzarlo per la prossima lettura. Se non trovi una nuova linea dovrai allocare un buffer più grande, copiare il contenuto di quello vecchio e solo dopo chiamare di nuovo la lettura.

MODIFICA: come menzionato nel commento, è possibile passare il ByteBuffer a CharsetDecoder al volo e tradurlo in CharBuffer (quindi aggiungere a StringBuilder o qualsiasi altra soluzione preffered).

+0

In questo modo devo comunque memorizzare un'intera riga come buffer di byte ... Per un attimo dimentico che ho a che fare con le righe ... E che il mio buffer è limitato (le linee possono essere molto lunghe). Come dovremmo fare? – gotch4

+1

È possibile utilizzare http://docs.oracle.com/javase/7/docs/api/java/nio/charset/CharsetDecoder.html#decode(java.nio.ByteBuffer,%20java.nio.CharBuffer,%20boolean) per convertire l'input al volo. Dovrai comunque gestire il buffer poiché potrebbe contenere caratteri rimanenti tra le letture. –

+0

Perfetto! Grazie, considera di aggiornare la risposta – gotch4

0

Prova Scanner:

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

FileChannel è InterruptibleChannel

+0

di nuovo, non ho bisogno di interrompibilità, ho bisogno di iniziare la lettura e una richiamata più tardi ... – gotch4

Problemi correlati