基础流的简单操作
之前学到的File我们只能操作文件夹和文件,却不能操作里面的内容。今天通过学习IO流之后,我们就可以操作文件里面的内容了。在Java中,处理字节流的两个基础的类是InputStream和OutputStream,而用于处理字符流的两个基础的类是Reader和Writer。所以其他的流类都是以这4个类为基础。首先就说一下InputStream和OutputStream。
FileInoutStream和FileOutputStream分别是InputStream和OutputStream的直接子类,我们可以叫它们为基础流或者低级流,基本流中构造中参数是介质。
1. InputStream的方法
read():读入一个字节并返回,包装为int,返回-1表示已读不到
close():关闭资源
首先从读文件的内容开始,例如我们先在D盘建立一个文件a.txt在里面写上abcde,那么我们怎么把这些内容读出来呢?看下面的代码。 |
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; publicclass Test { publicstaticvoid main(String[] args) { InputStream is = null; try {// 输入流文件必须存在 is = new FileInputStream("d:\\a.txt"); int i = is.read();//读第一个字节 System.out.println(i);//输出对应的内容,是int类型的如果想输出原来的内容 //把类型转换一下就可以了 System.out.println((char)i); //我们把两个异常合并到一起 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { }finally{ try {//关闭资源,同样需要抛出异常 is.close(); } |
执行结果:97 a |
另外的方法:
read(byte[] b) 一次读入尽可能多的字节去填满字节数组b,返回实际读到的字节数,-1表示已读不到。
read(byte[] b, int off, int len) 一次读入尽可能多的字节去填满字节数组b从off开始的len个空间。
如果我们想把abcde全部都读出来应该怎么办呢?这时我们可以借助循环,因为在read()方法中-1表示读不到了,所以我们可以这么做
int i = 0; while((i=is.read())!=-1){//如果不是-1代表下面还有字节 System.out.print((char)i); |
执行结果:abcde |
读的操作我们已经做到了,接下来就是往文件里面写内容。这时我们就需要使用OutpetStream这个流类。OutputStream类提供的方法:
write():写一个字节到流中
write(byte[] b):将字节数组中的数据写入流中
write(byte[] b, int off, int len):将字节数组中从off开始的length个字节写入到流中
flush():将缓冲中的字节立即发送到流中,同时清空缓冲
close():关闭输出流
写的操作和读区别不大,看一下代码:
import java.io.FileOutputStream; import java.io.OutputStream; OutputStream os = null; try {// 输出流:自己会新建一个文件 // true表示追加 false表示覆盖 默认是false os = new FileOutputStream("d:\\b.txt",true); os.write(97);// //下面的这两个我们只需要写一个就行了 //os.flush(); os.close(); |
执行结果根据我们执行的次数而定,因为我们加了true,如果执行一次结果就是a,两次就是aa,以此类推。 |
如果我们想把a.txt的内容复制到b.txt中应该怎么做呢?思路就是每当读一个a.txt中的字节,就往b.txt里面写。代码也非常简单。
package day11; import java.io.File; while((i = is.read())!=-1){ char ch = (char)i; os = new FileOutputStream(new File("d:\\b.txt"),true); os.write(ch); |
结果当然就是b.txt里面也是abcde |
上面我们实现了文件内容的复制,下面我们来完成压缩文件复制的操作,有了上面的代码我们会有一些思路。在下面的代码中为了更清晰的体现代码,我们将抛出异常都交给函数来完成,不再自己处理,但是不建议这样,现在只是为了让代码清晰,看下面代码:
publicclass TestCopyFile { publicstaticvoid main(String[] args) throws IOException { //调用下面的方法,左面是以存在的压缩包,右面是复制生成的压缩包 copyFile("d:\\day02.rar","d:\\test.rar"); //定义一个方法 publicstaticvoid copyFile(String file1,String file2) throws IOException{ FileInputStream fis = new FileInputStream(new File(file1)); FileOutputStream fos = new FileOutputStream(new File(file2)); int b = 0; // 读源文件,将读入的每个字节依次写入目标文件 while((b=fis.read())!=-1){ fos.write(b); // 流操作的最后一定要关闭 fis.close(); fos.close(); |
执行结果:在D盘有一个test.rar的压缩包,当然我们可以根据自己电脑来决定复制什么文件,如果文件很大的话,我们可以清楚的看到test.rar的大小会逐渐增大,这是因为我们是按字节来复制的,很显然这种复制方法是非常慢的,怎么提高复制的速度呢?一起看下吧! |
下面是改进的方法,改动的地方不是很大
intb = 0; //定义一个8K的数组 byte[] arrByte = newbyte[8*1024]; // 读源文件,将读入的每个字节依次写入目标文件,按每8K来复制 while((b=fis.read(arrByte))!=-1){ fos.write(arrByte); |
执行结果:如果文件很大的话,我们可以看到和上面的区别,就是复制速度变快了。 |
但是我们会发现一个问题,那就是复制之后的test.rar变大了一点,这是因为我们是按每8k来复制的,当day02.rar末尾的地方不够8k时,仍然会按照8k来复制,这样最后的8k里面就会自动填入数据,所以变大了,怎样解决这个问题呢?也很容易,我们只需要将上面的