88import java .nio .ByteBuffer ;
99import java .nio .channels .FileChannel ;
1010import java .util .ArrayList ;
11- import java .util .List ;
1211
1312final class BufferHolder {
1413 // DO NOT PASS OUTSIDE THIS CLASS. Doing so will remove thread safety.
@@ -23,18 +22,48 @@ final class BufferHolder {
2322 FileChannel channel = file .getChannel ()) {
2423 long size = channel .size ();
2524 if (mode == FileMode .MEMORY ) {
26- Buffer buf ;
2725 if (size <= chunkSize ) {
28- buf = new SingleBuffer (size );
26+ // Allocate, read, and make read-only
27+ ByteBuffer buffer = ByteBuffer .allocate ((int ) size );
28+ if (channel .read (buffer ) != size ) {
29+ throw new IOException ("Unable to read "
30+ + database .getName ()
31+ + " into memory. Unexpected end of stream." );
32+ }
33+ buffer .flip ();
34+ this .buffer = new SingleBuffer (buffer );
2935 } else {
30- buf = new MultiBuffer (size );
31- }
32- if (buf .readFrom (channel ) != buf .capacity ()) {
33- throw new IOException ("Unable to read "
34- + database .getName ()
35- + " into memory. Unexpected end of stream." );
36+ // Allocate chunks, read, and make read-only
37+ var fullChunks = (int ) (size / chunkSize );
38+ var remainder = (int ) (size % chunkSize );
39+ var totalChunks = fullChunks + (remainder > 0 ? 1 : 0 );
40+ var buffers = new ByteBuffer [totalChunks ];
41+
42+ for (int i = 0 ; i < fullChunks ; i ++) {
43+ buffers [i ] = ByteBuffer .allocate (chunkSize );
44+ }
45+ if (remainder > 0 ) {
46+ buffers [totalChunks - 1 ] = ByteBuffer .allocate (remainder );
47+ }
48+
49+ var totalRead = 0L ;
50+ for (var buffer : buffers ) {
51+ var read = channel .read (buffer );
52+ if (read == -1 ) {
53+ break ;
54+ }
55+ totalRead += read ;
56+ buffer .flip ();
57+ }
58+
59+ if (totalRead != size ) {
60+ throw new IOException ("Unable to read "
61+ + database .getName ()
62+ + " into memory. Unexpected end of stream." );
63+ }
64+
65+ this .buffer = new MultiBuffer (buffers , chunkSize );
3666 }
37- this .buffer = buf ;
3867 } else {
3968 if (size <= chunkSize ) {
4069 this .buffer = SingleBuffer .mapFromChannel (channel );
@@ -45,38 +74,27 @@ final class BufferHolder {
4574 }
4675 }
4776
48- /**
49- * Construct a ThreadBuffer from the provided URL.
50- *
51- * @param stream the source of my bytes.
52- * @throws IOException if unable to read from your source.
53- * @throws NullPointerException if you provide a NULL InputStream
54- */
55- BufferHolder (InputStream stream ) throws IOException {
56- this (stream , MultiBuffer .DEFAULT_CHUNK_SIZE );
57- }
58-
5977 BufferHolder (InputStream stream , int chunkSize ) throws IOException {
6078 if (null == stream ) {
6179 throw new NullPointerException ("Unable to use a NULL InputStream" );
6280 }
63- List < ByteBuffer > chunks = new ArrayList <>();
64- long total = 0 ;
65- byte [] tmp = new byte [chunkSize ];
81+ var chunks = new ArrayList <ByteBuffer >();
82+ var total = 0L ;
83+ var tmp = new byte [chunkSize ];
6684 int read ;
6785
6886 while (-1 != (read = stream .read (tmp ))) {
69- ByteBuffer chunk = ByteBuffer .allocate (read );
87+ var chunk = ByteBuffer .allocate (read );
7088 chunk .put (tmp , 0 , read );
7189 chunk .flip ();
7290 chunks .add (chunk );
7391 total += read ;
7492 }
7593
7694 if (total <= chunkSize ) {
77- byte [] data = new byte [(int ) total ];
78- int pos = 0 ;
79- for (ByteBuffer chunk : chunks ) {
95+ var data = new byte [(int ) total ];
96+ var pos = 0 ;
97+ for (var chunk : chunks ) {
8098 System .arraycopy (chunk .array (), 0 , data , pos , chunk .capacity ());
8199 pos += chunk .capacity ();
82100 }
0 commit comments