1、Channel
Java NIO的通道类似流,但又有些不同:
既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
通道可以异步地读写。
通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道。如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mvaslhbE-1617776150409)(image/1.png)]
Channel的实现:
这些是Java NIO中最重要的通道的实现:
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
FileChannel 用于从文件中读写数据。
DatagramChannel 能通过UDP读写网络中的数据。
SocketChannel 能通过TCP读写网络中的数据。
ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
2、RandomAccessFile
RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,既可以读取文件内容,也可以向文件输出数据。与普通的输
入/输出流不同的是,RandomAccessFile支持跳到文件任意位置读写数据,RandomAccessFile对象包含一个记录指针,用以标识当前读写处
的位置,当程序创建一个新的RandomAccessFile对象时,该对象的文件记录指针对于文件头(也就是0处),当读写n个字节后,文件记录指针
将会向后移动n个字节。除此之外,RandomAccessFile可以自由移动该记录指针。
RandomAccessFile包含两个方法来操作文件记录指针:
long getFilePointer():返回文件记录指针的当前位置
void seek(long pos):将文件记录指针定位到pos位置
RandomAccessFile类在创建对象时,除了指定文件本身,还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,该参
数有如下四个值:
r:以只读方式打开指定文件。如果试图对该RandomAccessFile指定的文件执行写入方法则会抛出IOException
rw:以读取、写入方式打开指定文件。如果该文件不存在,则尝试创建文件
rws:以读取、写入方式打开指定文件。相对于rw模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备,
默认情形下(rw模式下),是使用buffer的,只有cache满的或者使用RandomAccessFile.close()关闭流的时候儿才真正的写到文件。
rwd:与rws类似,只是仅对文件的内容同步更新到磁盘,而不修改文件的元数据。
//以读取、写入方式打开指定文件
RandomAccessFile raf = new RandomAccessFile("D:/demo/a.txt","rw");
//返回文件记录指针的当前位置
System.out.println("文件记录指针的当前位置:"+raf.getFilePointer());
//将文件记录指针定位到pos位置
raf.seek(100);
System.out.println("文件记录指针的当前位置:"+raf.getFilePointer());
运行结果:
文件记录指针的当前位置:0
文件记录指针的当前位置:100
使用RandomAccessFile进行简单的读取操作:
//以读取、写入方式打开指定文件
RandomAccessFile raf = new RandomAccessFile("D:/demo/a.txt","rw");
//创建一次读取的数量
byte[] bbuf = new byte[1024];
int hasRead = 0;
//循环读取文件里面的内容,直到没有内容
while ((hasRead = raf.read(bbuf)) > 0) {
System.out.println(new String(bbuf, 0, hasRead));
}
raf.close();
使用RandomAccessFile进行简单的写入操作:
//以读取、写入方式打开指定文件
RandomAccessFile raf = new RandomAccessFile("D:/demo/a.txt","rw");
//待写入的内容:
String[] arrays = new String[] { "Hello Hadoop", "Hello Spark", "Hello Hive" };
//将光标移到末尾
raf.seek(raf.length());
//追加写入内容
raf.write("append Content:\n".getBytes());
for (String arr : arrays) {
raf.write((arr + "\n").getBytes());
}
raf.close();
FileChannel getChannel() 返回与此文件关联的唯一的FileChannel对象。
FileChannel 用于读取,写入,映射和操作文件的通道。
3、基本的 Channel 示例
下面是一个使用FileChannel读取数据到Buffer中的示例:
//以读取、写入方式打开指定文件
RandomAccessFile aFile = new RandomAccessFile("D:/demo/a.txt","rw");
//通过RandomAccessFile得到FileChannel对象
FileChannel inChannel = aFile.getChannel();
//ByteBuffer 一个字节缓冲区。
//static ByteBuffer allocate(int capacity) 静态方法,分配一个新的字节缓冲区,得到字节缓冲区对象
ByteBuffer buf = ByteBuffer.allocate(48);
//abstract int read(ByteBuffer dst) 从该通道读取到给定缓冲区的字节序列。 返回值读取的字节数,可能为零,如果通道已达到流出端, 则为-1
int bytesRead = inChannel.read(buf);
//如果没有达到流出端,继续读
while (bytesRead != -1) {
System.out.println("Read " + bytesRead);
//翻转这个缓冲区。 该限制设置为当前位置,然后将该位置设置为零。 如果标记被定义,则它被丢弃。
buf.flip();
//boolean hasRemaining() 告诉当前位置和极限之间是否存在任何元素。
while(buf.hasRemaining()){
//abstract byte get() 相对 获取方法。
System.out.print((char) buf.get());
}
//public final Buffer clear()清除此缓冲区。 位置设置为零,限制设置为容量,标记被丢弃。
buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();
ic final Buffer clear()清除此缓冲区。 位置设置为零,限制设置为容量,标记被丢弃。
buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();
注意 buf.flip() 的调用,首先读取数据到Buffer,然后反转Buffer,接着再从Buffer中读取数据。下一节会深入讲解Buffer的更多细节。
本文详细介绍了Java NIO中的Channel特性,包括FileChannel、DatagramChannel、SocketChannel和ServerSocketChannel,强调了它们的异步读写和双向数据传输能力。同时,讲解了RandomAccessFile的使用,它支持随机读写并能自由移动文件记录指针。通过示例展示了如何使用FileChannel读取数据到Buffer以及RandomAccessFile进行读写操作。
1212

被折叠的 条评论
为什么被折叠?



