1 package com
.google
.appengine
.api
.files
;
3 import java
.io
.IOException
;
4 import java
.nio
.ByteBuffer
;
7 * Wraps a FileReadChannel to provide buffering of reads.
9 public class BufferedFileReadChannelImpl
implements FileReadChannel
{
11 private final FileReadChannel readChannel
;
12 private final int bufferSize
;
13 private final ByteBuffer buffer
;
14 private boolean encounteredEof
;
15 private final Object lock
= new Object();
17 public BufferedFileReadChannelImpl(FileReadChannel readChannel
, int bufferSize
) {
18 this.readChannel
= readChannel
;
19 this.bufferSize
= bufferSize
;
20 this.buffer
= ByteBuffer
.allocate(bufferSize
);
22 this.encounteredEof
= false;
25 private void makeEmpty() {
26 this.buffer
.position(buffer
.limit());
30 public int read(ByteBuffer dst
) throws IOException
{
32 if (encounteredEof
&& buffer
.remaining() == 0) {
35 if (dst
.remaining() == 0) {
36 if (buffer
.remaining() == 0) {
48 if (bufferHasMoreThanNeeded(dst
)) {
49 bytesRead
= readIntoShortBuffer(dst
);
51 bytesRead
= buffer
.remaining();
53 assert buffer
.remaining() == 0;
54 while (dst
.remaining() > bufferSize
&& !encounteredEof
) {
55 int bytesFromChannel
= readChannel
.read(dst
);
56 if (bytesFromChannel
== -1) {
57 encounteredEof
= true;
59 bytesRead
+= bytesFromChannel
;
62 if (dst
.remaining() > 0 && dst
.remaining() <= bufferSize
&& !encounteredEof
) {
64 bytesRead
+= readIntoShortBuffer(dst
);
67 return (bytesRead
== 0 && encounteredEof
) ?
-1 : bytesRead
;
71 private boolean bufferHasMoreThanNeeded(ByteBuffer dst
) {
72 return dst
.remaining() <= buffer
.remaining();
75 private int readIntoShortBuffer(ByteBuffer dst
) {
76 int oldLimit
= buffer
.limit();
77 int newLimit
= Math
.min(oldLimit
, buffer
.position() + dst
.remaining());
78 int bytesRead
= Math
.min(dst
.remaining(), buffer
.remaining());
79 buffer
.limit(newLimit
);
83 buffer
.limit(oldLimit
);
88 private void refillBuffer() throws IOException
{
89 assert buffer
.remaining() == 0;
91 int read
= readChannel
.read(buffer
);
94 encounteredEof
= true;
102 public boolean isOpen() {
103 return readChannel
.isOpen();
110 public void close() throws IOException
{
115 public long position() throws IOException
{
116 synchronized (lock
) {
117 long position
= readChannel
.position();
118 return position
- buffer
.remaining();
123 public FileReadChannel
position(long newPosition
) throws IOException
{
124 synchronized (lock
) {
125 long startingPosition
= position();
126 int relativePos
= (int) (newPosition
- startingPosition
);
127 if (relativePos
< buffer
.remaining() && relativePos
>= 0) {
128 buffer
.position(buffer
.position() + relativePos
);
132 readChannel
.position(newPosition
);