Java Reference
In-Depth Information
Buffers are an in-memory abstraction. To affect the outside world (e.g., the file or
network), we need to use a
Channel
, from the package
java.nio.channels
. Chan‐
nels represent connections to entities that can support read or write operations.
Files and sockets are the usual examples of channels, but we could consider custom
implementations used for low-latency data processing.
Channels are open when they're created, and can subsequently be closed. Once
closed, they cannot be reopened. Channels are usually either readable or writable,
but not both. The key to understanding channels is that:
• Reading from a channel puts bytes into a buffer
• Writing to a channel takes bytes from a buffer
For example, suppose we have a large file that we want to checksum in 16M chunks:
FileInputStream
fis
=
getSomeStream
();
boolean
fileOK
=
true
;
try
(
FileChannel
fchan
=
fis
.
getChannel
())
{
ByteBuffer
buffy
=
ByteBuffer
.
allocateDirect
(
16
*
1024
*
1024
);
while
(
fchan
.
read
(
buffy
)
!=
-
1
||
buffy
.
position
()
>
0
||
fileOK
)
{
fileOK
=
computeChecksum
(
buffy
);
buffy
.
compact
();
}
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
"Exception in I/O"
);
}
This will use native I/O as far as possible, and will avoid a lot of copying of bytes on
and off the Java heap. If the
computeChecksum()
method has been well imple‐
mented, then this could be a very performant implementation.
Mapped Byte Bufers
These are a type of direct byte buffer that contain a memory-mapped file (or a
region of one). They are created from a
FileChannel
object, but note that the
File
object corresponding to the
MappedByteBuffer
must not be used after the memory-
mapped operations, or an exception will be thrown. To mitigate this, we again use
try
-with-resources, to scope the objects tightly:
try
(
RandomAccessFile
raf
=
new
RandomAccessFile
(
new
File
(
"input.txt"
),
"rw"
);
FileChannel
fc
=
raf
.
getChannel
();)
{
MappedByteBuffer
mbf
=
fc
.
map
(
FileChannel
.
MapMode
.
READ_WRITE
,
0
,
fc
.
size
());
byte
[]
b
=
new
byte
[(
int
)
fc
.
size
()];
mbf
.
get
(
b
,
0
,
b
.
length
);
for
(
int
i
=
0
;
i
<
fc
.
size
();
i
++)
{
b
[
i
]
=
0
;
// Won't be written back to the file, we're a copy
}