IO流这个体系中,涉及到了很多设备,有硬盘、控制台、键盘、内存、打印机、扫描仪。。。,如果说,以客户为中心,那么我们的大客户就是内存了,所有这些输入输出设备都是为了辅助内存而存在的。
总体来说,这些外设分为3类,文件类、控制台、键盘输入,如果还要说一个,那就是网卡了,对于网卡暂时不讨论。 IO的I指的是Input,那么Input操作的对象时谁?IO的O指的是Output,那么Output操作的对象又是谁呢?这两个都是动词耶,他们必须要操作一个实体啊,不多想,这个实体就是内存了,具体点说是内存中某一个对象了。Input,就像你往水杯里面装水,Output,那就像你把杯子里面的水倒出来一样了,那么装水倒水这些动作,到底是属于我们的,还是属于杯子的呢???
以前,用到IO流中比较多的就是控制台和键盘了:System.out 和System.in,那么现在来看看文件操作。需求是:将“D:\\a.java"拷贝到"E:\\b.java",也就是说在E盘下创建一下叫b.java的文件,它具有和a.java一样的内容,那么这将是一个怎样的流程呢?1首先,要处理硬盘上面的文件,必须在内存中为这个文件建立一个File对象,与之映射,我们只用抽象的处理这个File对象,底层就会为我们具体的操作硬盘了。但是File对象
只能操作自己,无法和其他File对象交互,不可能说一个File对象将自己的内容直接发送给另一个File对象了,这时候流就出现了。
流程:源文件-源File对象-输入流对象-内存中转站-输出流对象-目的File对象-目的文件,而我们只需要操作输入流、中转站和输出流了,流和中转站都这么多,我们又该怎么选择呢?
2然后,就是寻找适合的流对象了和中转站了。java中的流按照输入输出,分为输入流和输出流,这个不用多说了。还有就是字节流和字符流,原本只有字节流的,因为内存里面本来就只能存储0101了,后来为了能方便操作字符,就在字节流上面进行了包装。再后来,为了各种需求和效率问题,又有了缓冲流、字节字符转换流...等等,就像以前只有泥巴路一样,后来为了走车子,有了柏油路,为了走火车,又有了铁路,为了走地铁,又有了地铁线路。。。。都是随着需求不断改变的。
上面的源文件a.java是纯文本字符的,所以选择字符输入流了,即Reader类,为了提高效率,选择BufferedReader,
目的文件b.java 也是纯文本的,所以徐那种字符输出流了,即Writer,为了提高效率,就选BufferedWriter了。
中转站怎么选呢?我操作文件时,是一行行操作,还是一个个字符,还是一块块的?算了,都试一试,看哪个的效率高了。一个个字符操作,用char;一行行的话
用个String;一块块的话,就用个char[]了。
3代码示例:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//为了方便看逻辑,将所有的异常都抛出去了。
public class CopyTextFile {
public static void main(String[] args) throws IOException{
long start1=System.currentTimeMillis();
copy_1();
long time1=System.currentTimeMillis()-start1;
System.out.println("一行行的读,耗时:"+time1);
long start2=System.currentTimeMillis();
copy_2();
long time2=System.currentTimeMillis()-start2;
System.out.println("一块块的读,耗时:"+time2);
long start3=System.currentTimeMillis();
copy_3();
long time3=System.currentTimeMillis()-start3;
System.out.println("一个个字符的读,耗时:"+time3);
}
public static void copy_1() throws IOException {
//1输入流:BufferedReader
BufferedReader bufr=new BufferedReader(new FileReader("D:\\a.java"));
//2输出流:BufferedWriter
BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\b1.java"));
//3:内存中转站
//①String:从输入流中读取一行暂存String,在将String写到输出流,记得换行和刷新
String line =null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
//关闭流:就像用完水龙头一样,要及时的关闭,免得浪费了资源
bufr.close();
bufw.close();
}
public static void copy_2() throws IOException{
//1输入流:BufferedReader
BufferedReader bufr=new BufferedReader(new FileReader("D:\\a.java"));
//2输出流:BufferedWriter
BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\b2.java"));
//3:内存中转站
//②char[]:从输入流读一块数据存到char[],再把这存的数据丢到输出流
char[]buf=new char[1024];
int num=0;
while((num=bufr.read(buf))!=-1)
{
bufw.write(buf,0,num);
}
//关闭流:就像用完水龙头一样,要及时的关闭,免得浪费了资源
bufr.close();
bufw.close();
}
public static void copy_3() throws IOException{
//1输入流:BufferedReader
BufferedReader bufr=new BufferedReader(new FileReader("D:\\a.java"));
//2输出流:BufferedWriter
BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\b3.java"));
//3:内存中转站:
//③char字符:从输入流读一个字符到char,在将char写入到输出流,(由于char会被自动提示为int,所以需要使用int进行转换)
int ch=0;
while((ch=bufr.read())!=-1){
bufw.write(ch);
}
//关闭流:就像用完水龙头一样,要及时的关闭,免得浪费了资源
bufr.close();
bufw.close();
}
}
一行行的读,耗时:0
一块块的读,耗时:0
一个个字符的读,耗时:0
原来使用了Buffer,这几种方式都在在内存里面,速度比较快,时间几乎都是0毫秒了。但是,对于文本文件,建议用一行行的读,可以有效的提取数据。
待续。。。。
换个一个500kb的文件测试,随机一个结果是:
一行行的读,耗时:64
一块块的读,耗时:7
一个个字符的读,耗时:20
发现一行行读最慢,其次一个个读写,最快一块块。有业务逻辑,需要判断某行内容,一行行读吧,需要判断某一个字符,一个个字符读吧,如果只是拷贝文件,建议一块块的读,而且不改变文件大小。