Question

I am trying the AsynchronousFileChannel JAVA 7 API to write a file in an async manner, however I could not find an easy way to append to the file.

The API description states that AsynchronousFileChannel doesn't maintain the file position and you have to specify the file position. This means that you have to maintain a global file position value. Moreover this global state should be atomic so that you are correctly incrementing.

Is there a better way of doing updates using the AsynchronousFileChannel?

Also, can someone please explain the use of the Attachment object in the API?

public abstract <A> void write(ByteBuffer  src,
             long position,
             A attachment,
             CompletionHandler<Integer ,? super A> handler)

The javadoc says: attachment - The object to attach to the I/O operation; can be null

What is the use of this attachment object?

Thanks!

Was it helpful?

Solution

What is the use of this attachment object?

An attachment is an object that you can pass along to the completion handler; see it as an opportunity to provide context. You can use it for pretty much anything you can imagine, from logging to synchronising or just plain ignoring it.

I am trying the AsynchronousFileChannel JAVA 7 API to write a file in an async manner, however I could not find an easy way to append to the file.

Async is usually a little trickier, and appending to a file is an inherently serial process. That said, you can do it in parallel, but you'll have to do some bookkeeping about where to append the next buffer contents. I imagine it might look something like this (using the channel itself as the 'attachment'):

class WriteOp implements CompletionHandler<Integer, AsynchronousFileChannel> {
  private final ByteBuffer buf;
  private long position;

  WriteOp(ByteBuffer buf, long position) {
    this.buf = buf;
    this.position = position;
  }

  public void completed(Integer result, AsynchronousFileChannel channel) {
    if ( buf.hasRemaining() ) { // incomplete write
      position += result;
      channel.write( buf, position, channel, this );
    }
  }

  public void failed(Throwable ex, AsynchronousFileChannel channel) {
    // ?
  }
}

class AsyncAppender {
  private final AsynchronousFileChannel channel;
  /** Where new append operations are told to start writing. */
  private final AtomicLong projectedSize;

  AsyncAppender(AsynchronousFileChannel channel) throws IOException {
    this.channel = channel;
    this.projectedSize = new AtomicLong(channel.size());
  }

  public void append(ByteBuffer buf) {
    final int buflen = buf.remaining();
    long size;
    do {
      size = projectedSize.get();
    while ( !projectedSize.compareAndSet(size, size + buflen) );

    channel.write( buf, position, channel, new WriteOp(buf, size) );
  }
}

OTHER TIPS

I have just used the channel.size() as the position. In my case the file is NOT modyfied by multiple threads, only one thread opens and writes to the file, this seems to work so far.

If somebody knows this to be a wrong thing to do, please chime in.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top