一、输入输出的概念 点击此处返回总目录 二、字节输出流OutputStream 三、FileOutputStream 四、IO中的异常处理 一、输入输出的概念 前面讲了如何操作文件和目录。从现在开始讲如何往文件中写数据读数据。 首先要搞明白什么叫做Input,什么叫做Output。 Input、Output是对于程序来说的。读取文件中的数据叫做输入,把数据写到文件中叫做输出。 Input :输入 从文件(硬盘)------->程序(内存) Output:输出 从程序(内存)------->文件(硬盘) 进行文件内容的操作需要通过Java中提供的两组数据流的操作类完成: 字节操作流:OutputStream、InputStream 字符操作流:Writer、Reader 流对象学习技巧: 流对象都是相辅相成的:有输入必有输出,有输出必有输入;输出能输出什么,输入就能输入什么。所以学会了一个方向,另一个方向完全能够明白。 流对象的使用步骤: 1. 创建流的子类对象,绑定数据目的或数据源 2. 调用流对象的方法 3. close() 二、字节输出流OutputStream java.io.OutputStream是抽象类,是所有字节输出流的父类。作用是从java程序写出到文件。 OutputStream每次只操作文件中的1个字节。 字节输出流可以写任意文件。 常用方法: 这个类的方法都是写文件的一下方法,一共也没几个。所有的子类都得具有这些方法。 1. write(int b) //写入1个字节。int型可以砍掉3个字节变为byte。要写入的字节是参数b的八个低位。 b的 24 个高位将被忽略。【例1】【例2】【例3】 2. write(byte[] b) //写入字节数组。【例4】【例5】。写入字符数组的简便方式:【例6】 3. write(byte[] b , int off , int len) //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。【例7】 4. close() //关闭流对象,并且释放与此流相关的资源。java当中的流对象,在操作文件的时候,自己并不 做,而是使用的操作系统的功能,当流用完了,系统资源必须要释放掉。如果不close(),文件 想删都删不了。 因为是抽象类,所以要通过子类对象来学习父类的方法。OutputStream类的常用子类有ByteArrayOutputStream(字节数组输出流,这个流可以写字节数组)、FileOutputStream(这个流用于写文件)、FilterOutputStream(跟过滤器有关系)、ObjectOutputStream(这个用来写对象)、OutputStream(其他包中的一个流,跟我们没什么关系)、PipeOutputStream(管道流)等。 三、FileOutputStream 1)构造方法 作用:绑定输出的输出目的。 1. FileOutputStream(File file) //参数为File类型的对象。当原先有文件时,会覆盖掉(先删除原来的,再创建新的) 2. FileOutputStream(String name) //参数为String类型的对象。覆盖方式。 3. FileOutputStream(File file,boolean append) //当append为true时,会追加写,不再覆盖。【例8】 4. FileOutputStream(String name,boolean append) //String,追加方式。 注: 1.当文件不存在时,构造方法会先创建文件。 2.当原先有文件时,会覆盖掉(先删除原来的,再创建新的)。 2)继承过来的方法: 例1:write(int b)
package cn.itcast.demo01; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\a.txt"); //写数据的目的文件。就是指写到哪里。 ops.write(100); ops.close(); } } |
运行结果: 打开e:\a.txt,发现里面只有一个字母'd'。 分析: 100的二进制为:00000000 00000000 00000000 01100100 ,低字节为01100100。所以在硬盘中存的是byte 100,当打开记事本,记事本是文本工具,文本工具开启的一瞬间都会去走编码表,byte 100 对应的是字符'd',所以看到的是字符'd'。 例2:write(int b)
package cn.itcast.demo01; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\a.txt"); //写数据的目的文件。就是指写到哪里。 ops.write(1124); ops.close(); } } |
运行结果: 打开e:\a.txt,发现里面只有一个字母'd'。 结果分析: 1124的二进制为:00000000 00000000 00000100 01100100 ,低字节为01100100。所以在硬盘中存的是二进制01100100,即byte 100,当打开记事本,记事本是文本工具,文本工具开启的一瞬间都会去走编码表,100对应的是字符'd',所以看到的是字符'd'。 在一个文本当中,一个汉字占两个字节,数字占1个字节。所以如果a.txt中存储了"吃",则a.txt为2个字节。如果a.txt中存储了"100",则a.txt为3个字节。 要想打开a.txt,能够看到"100",使用write()怎么存?一个write写一个字节,要想看到100,即3个字节,需要存三次。【例3】 例3:write(int b)
package cn.itcast.demo01; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\a.txt"); //写数据的目的文件。就是指写到哪里。 ops.write(49); //低字节二进制对应十进制为49,ASCII码为'1' ops.write(48); //十进制48对应ASCII码为'0' ops.write(48); ops.close(); } } |
运行结果: 打开a.txt,能够看到"100" 例4:
package cn.itcast.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\aaa.txt"); byte[] b = {68,65,66,67}; ops.write(b); //存进去的分别是68,65,66,67,当打开TXT时,查看ASCII码表,显示DABC ops.close(); } } |
例5:
package cn.itcast.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\aaa.txt"); byte[] b = {-68,-65,-66,-67}; ops.write(b); ops.close(); } } |
运行结果: 打开aaa.txt,能够看到"伎窘" 分析:负数代表汉字,两个字节表示一个汉字。所以显示两个汉字。 例6:写入字符数组的简便方式。
package cn.itcast.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\aaa.txt"); ops.write("helloworld".getBytes()); ops.close(); } } |
运行结果: 打开aaa.txt,能够看到"helloworld"。 例7:
package cn.itcast.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\aaa.txt"); byte[] b = {65,66,67,68}; ops.write(b,1,2); //从1开始,写两个。 ops.close(); } } |
运行结果: 打开aaa.txt,能够看到"BC" 例8:追加方式
package cn.itcast.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\aaa.txt",true); //追加方式 ops.write("helloworld".getBytes()); ops.close(); } } |
运行结果: 假设执行之前aaa.txt中有内容"aa",则执行之后内容为"aahelloworld"。 例9:怎么写入换行。通过"\r\n"来换行,可以写在上一行的后面,也可以写在下一行的前面。
package cn.itcast.demo02; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) throws IOException { OutputStream ops = new FileOutputStream("e:\\aaa.txt",true); ops.write("nihao\r\n".getBytes()); //写完之后换行 ops.write("lijing".getBytes()); ops.write("\r\nbuhao".getBytes()); //换行之后再写 ops.close(); } } |
运行结果: nihao lijing buhao 四、IO中的异常处理 IO流中遇到异常,需要使用try catch finally语句处理掉。 1.标准写法
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { OutputStream ops = null; try{ ops = new FileOutputStream("e:\\abc.txt"); ops.write(76); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException("文件写入失败,请重试"); }finally{ try{ if (ops !=null) ops.close(); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException("文件关闭失败"); } } } } |
2.为什么这么写 首先:写语句。
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { OutputStream ops = new FileOutputStream("e:\\abc.txt"); ops.write(76); ops.close(); } } |
结果红色部分报错,因为没有进行异常处理。 改进:
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { try{ OutputStream ops = new FileOutputStream("e:\\abc.txt"); //第一句 ops.write(76); //第二句 ops.close(); //第三句 }catch(IOException e){ e.printStackTrace(); } } } |
虽然上面的程序不报错,但是有问题。当执行了第二句出现异常之后,就不会执行第三句,结果资源就不能释放了。可以使用finally语句释放资源。 继续改进:
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { try{ OutputStream ops = new FileOutputStream("e:\\abc.txt"); ops.write(76); }catch(IOException e){ e.printStackTrace(); }finally{ ops.close(); //这句报错。找不到ops变量。 } } } |
虽然将ops.close()放到了finally进行处理,但是程序报错了。因为变量ops的生命周期在try的大括号内。所以应当在try外声明变量,在try内建立对象。这样就可以扩大变量的作用域了。 继续改进:
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { OutputStream ops = null; try{ ops = new FileOutputStream("e:\\abc.txt"); ops.write(76); }catch(IOException e){ e.printStackTrace(); }finally{ ops.close(); //这句报错。 } } } |
放到外面之后又报错了。close()方法抛异常。释放资源有可能也出错,但是程序没有处理。所以应当增加对close()的异常处理。 继续改进:
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { OutputStream ops = null; try{ ops = new FileOutputStream("e:\\abc.txt"); ops.write(76); }catch(IOException e){ //第一个catch。 e.printStackTrace(); }finally{ try{ ops.close(); }catch(IOException e){ //第二个catch e.printStackTrace(); } } } } |
到这里就大致写完了,但是还有一些细节需要处理。 第一个细节就是catch怎么处理? 首先要打印出异常信息,这个不用多说。 但是这样就够了么?比如,正在往一个U盘上写东西,突然U盘被拔掉了。这种情况下再怎么用catch处理都不行,程序根本处理不了,后面再继续做也没有什么意义了。所以这里应当抛出一个RuntimeException,让程序停下来。 第二个catch,当close()的时候发生问题,比如系统占着资源呢。这时候也没办法,还是要把系统停下来。 继续改进:
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { OutputStream ops = null; try{ ops = new FileOutputStream("e:\\abc.txt"); //第一句 ops.write(76); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException("文件写入失败,请重试"); }finally{ try{ ops.close(); //第二句 }catch(IOException e){ e.printStackTrace(); throw new RuntimeException("文件关闭失败"); } } } } |
第二个细节就是,如果流对象建立失败了,还需要关闭资源么?第一句都没有成功,new 对象失败了,也就是没有占用系统资源。但是最后还是执行第二句,这样就多此一举。所以应该加一个判断。 继续改进:
package cn.itcast.demo03; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; public class Test { public static void main(String[] args) { OutputStream ops = null; try{ ops = new FileOutputStream("e:\\abc.txt"); ops.write(76); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException("文件写入失败,请重试"); }finally{ try{ if (ops !=null) ops.close(); }catch(IOException e){ e.printStackTrace(); throw new RuntimeException("文件关闭失败"); } } } } |
以上就是最终版了。代码量比较大~~~~ |