How to use AsynchronousFileChannel to read efficiently in StringBuffer

So, you know that you can use AsynchronousFileChannel to read the entire file in String:

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

Suppose now that I do not want to allocate whole ByteBuffer , but read line by line. I could use a fixed-width ByteBuffer and remind read many times, always copying and adding to a StringBuffer until I get a new line ... My only problem: because the file encoding that I am reading may be multi-byte per character (something UTF ), it may happen that the bytes read end with an incomplete character. How can I make sure that I convert the correct bytes to strings and not mess up the encoding?

UPDATE: the answer is in the comment of the selected answer, but basically points to CharsetDecoder .

+5
source share
2 answers

If you have a clear ASCII delimiter that you have in your case (\ n), you do not need to worry about an incomplete string, as this character maps to one byte (and vice versa).

So, just find the "\ n" bytes in your input and read and convert anything to String. Loop until new lines appear. Then combine the buffer and reuse it for the next read. If you do not find a new line, you will have to allocate a larger buffer, copy the contents of the old one and only then invoke reading again.

EDIT: As mentioned in the comment, you can pass the ByteBuffer to CharsetDecoder on the fly and translate it into a CharBuffer (then add to StringBuilder or whatever is proposed for the solution).

+1
source

Try the scanner:

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

FileChannel - InterruptibleChannel

0
source

Source: https://habr.com/ru/post/1233965/


All Articles