本文主要讲述IO与NIO的使用及异同,通过具体的代码实例,熟悉用法;
一、IO
Java中IO布局如图1所示:
按流向区分
程序读(即向内存写),为输入流;程序写(即从内存写),为输出流;按操作单元区分
以单个字节为单位,为字节流;多个字节统一操作,为字符流;
字节流:处理所有数据类型,图片、视频和音频;
字符流:只能处理文本数据;-
按功能区分
节点流:数据与程序直接连接,如图2为常见的节点流:
处理流:
缓冲流(BufferInputStream 增加缓冲功能,提高效率)
转换流(InputStreamReader 实现字节流和字符流的转换)
数据流(DataInputStream 直接操作基本类型的数据) 流操作之四部曲
1 数据源:InputStream Reader 数据汇 :OutputStream Writer
2 纯本文:Read Writer 非纯本文:InputStream OutStream
3 数据源设备:磁盘(File) 内存(Memory)键盘(System.in)
数据汇设备:磁盘(File) 内存(Memory)屏幕(System.out)
4 提高效率:利用转换流中的BufferReader等实例代码(列出目录信息)
public class FileDictory {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//此处注意转义字符
File dir=new File("D:\\From-phone\\pic\\info");
List<File> list = new ArrayList<File>();
getDictory(dir,list);
writeToFile(list,new File(dir,"crossinfo.txt"));
}
public static void print(List<File> list){
for(File f : list){
System.out.println(f.getAbsolutePath());
}
}
public static void getDictory(File dir,List<File> list){
File[] files = dir.listFiles();
for(File f: files){
if(f.isDirectory())
getDictory(f,list);
else
list.add(f);
}
}
// 操作流的基本框架
public static void writeToFile(List<File> list,File file) throws IOException {
// 外部创建引用,内部实例化
BufferedWriter bw = null;
try{
bw = new BufferedWriter(new FileWriter(file));
for(File f:list){
bw.write(f.getAbsolutePath());
bw.newLine();
}
}
catch(IOException e){
throw e;
}
finally{
// 流释放检查
try{
if(bw!=null){
bw.close();//不同代码块的访问
}
}
catch(IOException e){
throw e;
}
}
}
}
二、NIO
核心对象
标准NIO的核心对象为Buffer和Channel,网络NIO的核心对象为Selector;
应用程序直接接触为Buffer,不与Channel进行交流;Buffer的写读模式切换
Buffer本身为一个数组,与普通数组不同的是具有position、limit和capacity三个参数,丰富其功能;
写模式时,limit和capacity为数组长度,position随着写过程进行不断叠加;
写读转换时,limit为写过程结束时position所在位置,capacity不变,position反转为数组起始位置;
具体过程参照Buffer工作原理Buffer的clear和compact方法
clear将缓冲区数据全部清空,compact将缓冲区未读数据全部移动到缓冲区起始位置;Channel的特点
双向通道,可以实现读写功能;应用程序不直接访问Channel对象;Selector对象
Selector对象详解实例代码(文件拷贝)
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("source.txt");
FileOutputStream fos = new FileOutputStream("destination.txt");
FileChannel inCha = fis.getChannel();
FileChannel outCha = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(true){
int res = inCha.read(buffer);
if(res == -1){
break;
}
// 实现写读模式切换
buffer.flip();
outCha.write(buffer);
buffer.clear();
}
inCha.close();
outCha.close();
fis.close();
fos.close();
}
三、IO与NIO的异同
IO是面向流的,NIO是面向缓冲区的。
IO的各种流是阻塞的,NIO是非阻塞模式。
Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。