概述
本篇博客向大家介绍的是如何运用java中的Channel进行文件读写,也就是说明如何通过Channel将字符串写到文件中,以及怎么把文件中的内容以字符串的形式读出来。具体地,我会介绍关于Channel和缓冲区的一些内容。
什么是通道
那么肯定就有一些同学不太知道什么是通道(Channel),所以在开始介绍之前,我们首先要对通道有一个说明。由 java.nio.channels 包定义的,也就是说Channel是java New I/O中的一种,Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel本身不能直接访问数据, Channel 只能与Buffer 进行交互。
如何获取通道
获取通道的方式有很多,这里只介绍其中一种,就是对支持通道的对象调用getChannel() 方法。支持通道的类如下:
- FileInputStream
- FileOutputStream
- RandomAccessFile
- DatagramSocket
- Socket
- ServerSocket
Channel策略主要思想
从文件中读:我们知道文件是可以以流的方式打开的,然后用流的getChannel() 方法即可以获取通道。然后用一个固定大小的缓存区多次从通道中读出内容即可。
往文件里写:同样的以流的方式打开文件,然后用流的getChannel() 方法即可以获取通道,之后再将要写入的字符串放入缓存区中,缓存区的内容通过通道就可以写到文件中去了。
缓冲区的一些内容
以下内容来自缓冲区(Buffer)这篇博客将缓冲区介绍的清晰明了,我截取其中一些内容放到这里方便大家看。
1、缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对I/O的数据做临时存储,这部分预留的内存空间叫缓冲区。使用缓冲区有两个好处:减少实际物理读写次数;缓冲区在创建时就被分配内存,这块内存区域一直被重用,可以减少动态分配和回收内存的次数。
2、所有缓冲区都有4个属性:capacity、limit、position、mark,并遵循mark<=position<=limit<=capacity,下表时对这4个属性的解释:
字段 | 作用 |
---|---|
position | 当前读到的位置 |
limit | 当前写到的位置 |
capacity | 容量 |
mark | 标记,调用mark()来设置mark=position,在调用reset()可以让position恢复到标记位置 |
3、一些重要方法
方法 | 描述 |
---|---|
flip() | limit=position,position=0,mark=-1;将缓冲区状态由存数据变为准备取数据 |
limit(),limit(10) | 前者get,后者set |
hasRemaining() | return position < limit,是否还有未读内容 |
Channel策略实现方法
从文件中读:首先我们通过FileInputStream f1 = new FileInputStream(filename);一句获取文件的读入流。然后利用FileChannel fc1 = f1.getChannel();获取读入流的通道。之后就是声明一个缓冲区,因为是字节流,所以我们声明一个bytebuffer,如:ByteBuffer b1 = ByteBuffer.allocate(1024);1024代表缓冲区的大小为1024字节,可以根据自己需要更改的。然后,调用FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。read()方法返回的int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。至此我们已将一部分内容读入到了bytebuffer中,不过我们的最终目的是将内容读入到字符串中,所有要进行一个转换。另外,缓冲区太小导致不能一次读完内容的时候还要清空缓存区多次读取。
往文件里写:同样先通过FileOutputStream f1 = new FileOutputStream(filename);获取文件的输出流,然后输出流的getChannel() 方法即可以获取通道,之后通过ByteBuffer buffer = ByteBuffer.wrap(outString.getBytes());将要写入的字符串放入缓存区中,最后调用fc1.write(buffer);就完成写文件了。
代码展示
package readandwrite;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Channel {
public String myread(String filename) throws Exception {
// TODO 自动生成的方法存根
long starttime = System.currentTimeMillis();
StringBuilder result = new StringBuilder();
try {
FileInputStream f1 = new FileInputStream(filename);
FileChannel fc1 = f1.getChannel();
ByteBuffer b1 = ByteBuffer.allocate(1024);//初始化缓冲区大小
while (fc1.read(b1) != -1) {
int temp = b1.limit();
b1.flip();
while (temp != 0 && b1.hasRemaining()) {//这里temp不为0是为了确保缓存区的有效内容不为空
result.append((char)b1.get());
}
b1.clear();
}
fc1.close();
f1.close();
} catch (Exception e) {
// TODO: handle exception
throw new Exception(e.toString());
}
long endtime = System.currentTimeMillis();
System.out.println("Channel策略读文件花费了:" + (endtime - starttime) + "ms");
return result.toString();
}
public void mywrite(String outString, String filename) throws Exception {
// TODO 自动生成的方法存根
long starttime = System.currentTimeMillis();
try {
FileOutputStream f1 = new FileOutputStream(filename);
FileChannel fc1 = f1.getChannel();
ByteBuffer buffer = ByteBuffer.wrap(outString.getBytes());
fc1.write(buffer);
fc1.close();
f1.close();
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
throw new Exception(e.toString());
} catch (IOException e) {
// TODO: handle exception
throw new Exception(e.toString());
}
long endtime = System.currentTimeMillis();
System.out.println("Channel策略写文件花费了:" + (endtime - starttime) + "ms");
}
public static void main(String[] args) {
String outfilename = "src\\txt\\cd.txt";
String outString = "This is channel strategy!";
Channel myChannel = new Channel();
try {
myChannel.mywrite(outString, outfilename);
System.out.println(myChannel.myread(outfilename));
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}