前言
IO流即输入流和输出流,我们对InputStream进行读操作,对OutputStream进行写操作。我们可以将流分为字节流和字符流,字节流处理一些二进制文件以字节为处理单位
比如图片,音乐,视频,word文档等,字符流处理一些文本文件以char为处理单位
比如说txt文件、java文件、cpp等文本文件;
节点流(文件流)
接下来我们介绍一下文件流(FileInputSteam、FileOutputSteam、FileWriter、FileReader)。
(1) 文件字节流
这里我们利用FileInputStream和FileOutputStream实现复制图片的功能。注意:输入流指定的文件必须已经存在,输出流指定的文件若存在会实现覆盖,若不存在会自动创建。
@Test
public void test1() throws IOException {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
byte[] bytes = new byte[1024];
int len;
try {
fileInputStream = new FileInputStream("binary/Norway.jpg");
fileOutputStream = new FileOutputStream("binary/copy.jpg");
long begin = System.currentTimeMillis();
while((len = fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
System.out.println("执行花费:"+(System.currentTimeMillis()-begin));// 87ms
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream!=null){
fileInputStream.close();
}
if(fileOutputStream!=null){
fileOutputStream.close();
}
}
}
上述代码我们看见了一个read方法,它的作用是从输入流中读取数据。当read返回值为 -1 的时候代表已经读完。
(2) 文件字符流
这里我们实现复制文本文件.
@Test
public void test2() throws IOException {
String src = "binary/杂文.txt";
String dest = "binary/copy.txt";
copyFile(src,dest);
}
private void copyFile(String src,String dest) throws IOException{
FileReader reader = null ;
FileWriter writer = null;
try{
reader = new FileReader(src);
writer = new FileWriter(dest);// 默认是覆盖不是追加
char[] c = new char[1024];
int len;
long begin = System.currentTimeMillis();
while((len = reader.read(c))!=-1){
writer.write(c,0,len);
}
long end = System.currentTimeMillis();
System.out.println("执行一共花费:"+(end-begin)+"ms");// 93ms
}catch (Exception e){
System.out.println(e);
} finally {
if(reader!=null){
reader.close();
}
if(writer!=null){
writer.close();
}
}
}
处理流
下面我们介绍缓存流和转换流
缓存流
我们很少直接使用文件流处理文件,而是将其包装成一个缓存流。缓存流内部保存一个8KB大小的空间,每次先从硬盘读取文件到缓存中比从硬盘中直接读取效率更高。下面给出示例代码:
private void copyFileByBuffer(String src,String dest) throws IOException{
FileReader reader = null ;
FileWriter writer = null;
try{
reader = new FileReader(src);
writer = new FileWriter(dest);
BufferedReader bufferedReader = new BufferedReader(reader);
BufferedWriter bufferedWriter = new BufferedWriter(writer);
char[] c = new char[1024];
int len;
long begin = System.currentTimeMillis();
while((len = bufferedReader.read(c))!=-1){
bufferedWriter.write(c,0,len);
}
long end = System.currentTimeMillis();
System.out.println("执行一共花费:"+(end-begin)+"ms");// 78ms
}catch (Exception e){
System.out.println(e);
} finally {
if(reader!=null){
reader.close();
}
if(writer!=null){
writer.close();
}
}
}
小提示: public void flush()throws IOException
刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。close方法返回前也会强制写出缓存中所有的数据到预期目标。
转换流
转换流可以帮助我们实现字节流到字符流之间的转换,转换的同时也可以执行编码格式(上述创建FileReader也可以指定charset,默认utf-8)
private void change(String src,String dest) throws UnsupportedEncodingException, FileNotFoundException {
FileInputStream fileInputStream = new FileInputStream(src);
FileOutputStream fileOutputStream = new FileOutputStream(dest);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"gbk");
}
对象流
我们有时需要将Java对象转换成一个字节流(序列化),将字节流转换成一个Java对象(反序列化)。在Java中要实现序列化和反序列化,必须要实现Serializable接口(或Externalizable 接口)。
下面文字摘自宋红康老师的课件:
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:private static final long serialVersionUID;
serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
RandomAccessFile 类
相较上述的类它有以下区别
- 一个类同时提供了读和写的方法
- 多了一个游标的功能,在游标开始的位置进行部分覆盖(非全覆盖)。
@Test
public void test2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("binary/hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
raf1.write("xyz".getBytes());//实现3 4 5位置被覆盖为"xyz"
System.out.println(raf1.getFilePointer());// 获取游标所在的位置
raf1.close();
}
NIO和IO多路复用
待了解