10---IO异常处理+Properties+缓冲流+字节转换流+序列化流+打印流+杂流

1、IO异常的处理(JDK1.7前后)

1、JDK1.7以前的IO异常处理

/*
    JDK1.7以前的
        1.创建IO流的时候发现FileInputStream有异常,选择try...catch
        2.在finally中写上关闭IO流语句后,且作用域不够,故将fis的定义放到try外面,
        3.发现fis需要赋初值,故赋值为null
        4.当fis为null值的时候,没办法调用close语句,故在finally中先判断fis!=null才去关流
        5.close又有异常,选择try...catch
        6.使用IO流读写数据又有异常,抓异常,添加catch分支(Add Enter的第一项)
 */
public static void test01() {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream("day10demo/abc/1.txt");
        int read = fis.read();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2、JDK1.7以前的异常处理
/*
    JDK1.7的处理方式
        自动关流
        try (创建流的代码,可以有多条创建语句) {
            操作流的代码
        } catch (异常类名 变量名) {

        }
 */
public static void test02() {
    try (FileInputStream fis = new FileInputStream("day10demo/abc/1.txt");
         FileOutputStream fos = new FileOutputStream("day10demo/abc/2.txt");
    ) {
        int read = fis.read();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2、Properties

1、概念:

(1)java.util.Properties 继承于 Hashtable ,来表示一个持久的属性集。

(2)Properties实现了Map接口,而Map接口就是一个双列集合。键和值都是字符串(作为集合的使用)

 	Map
    ↑实现
Hashtable
    ↑继承
Properties

(3)可以将Properties中的数据通过IO流保存到文件,也可以从文件中加载数据保存到Properteis中(和IO流的关联使用)

2、Properties作为集合的基本使用

​ Properties具有父类Map的方法。但也有其特有的方法

Object setProperty(String key, String value) 添加键和值
String getProperty(String key) 通过键找值
Set<String> stringPropertyNames() 获取所有的键

public static void main(String[] args) {
    // 1.创建Properties对象
    Properties pp = new Properties();

    // 2.调用方法
    // Object setProperty(String key, String value) 添加键和值
    pp.setProperty("name", "蔡徐坤");
    pp.setProperty("age", "22");
    pp.setProperty("address", "泰国");
    System.out.println(pp); // {address=泰国, name=蔡徐坤, age=22}

    // String getProperty(String key) 通过键找值
    String name = pp.getProperty("name");
    String age = pp.getProperty("age");
    String address = pp.getProperty("address");
    System.out.println(name + ":" + age + ":" + address);

    // 遍历Properties,相当于遍历Map
    // Set<String> stringPropertyNames() 获取所有的键
    // 1.得到所有的键
    Set<String> keySet = pp.stringPropertyNames();
    // 2.遍历得到每个键
    for (String key : keySet) {
        // 3.通过一个键找到一个值
        String value = pp.getProperty(key);
        System.out.println(key + "::" + value);
    }
}
3、Properties保存和加载文件
(1)保存数据到文件
void store(OutputStream out, String comments) 将Properties中的键值对数据保存到文件
    //OutputStream out: 字节输出流
    //String comments: 往文件写注释内容
public static void testStore() throws IOException {
    // 1.创建Properties
    Properties pp = new Properties();
    // 2.往Properties中存储数据
   pp.setProperty("小明","18");
   pp.setProperty("小花","19");
   pp.setProperty("小白","20");
   pp.setProperty("小李","21");

    // 3.调用store方法将数据写入流中
    // void store(OutputStream out, String comments) 将Properties中的键值对数据保存到文件
        // OutputStream out: 字节输出流
        // String comments: 往文件写注释内容
    FileOutputStream fos = new FileOutputStream("day10demo/abc/info.properties");
    pp.store(fos, "I am zhushi");
}

以下是info.propertise文件内容

​ 其中’‘#‘’是注释的标记;\u开头,为unicode码,表示后面的字符为中文

#I am zhushi
#Thu Jul 25 21:02:28 CST 2019
\u5C0F\u660E=18
\u5C0F\u674E=21
\u5C0F\u767D=20
\u5C0F\u82B1=19
(2)从流中加载数据到Properties中
void load(InputStream inStream) 从流中加载数据到Properties中

依据上述的info.properties文件,从该文件中读取数据到流中并加载到pp(Properties对象)中

public static void main(String[] args) throws IOException {
	// 1.创建Properties对象
    Properties pp = new Properties();
	
    // 2.创建一个文件输入流,并调用load方法
    // void load​(InputStream inStream) 从流中加载数据到Properties中
    FileInputStream fis = new FileInputStream("day06/abc/info.properties");
    pp.load(fis);
    System.out.println(pp);//{小明=18, 小李=21, 小白=20, 小花=19}

}

/*输出结果
{小明=18, 小李=21, 小白=20, 小花=19}
*/

3、缓冲流

1、概念

​ 我们知道在操作基本流的时候使用不带数组读取的次数很多,效率低;而带数组,会减少读取次数,提高效率。
既然带数组可以提高效率,Java就自己写好了4个类,这四个类带数组,这个数组称为缓冲区,这四个类叫做缓冲流

基本流:           字节流                             字符流
   输入流         FileInputStream                    FileReader

   输出流         FileOutputStream                   FileWriter

​ 这4个流称为缓冲流,高效流,类名都是以Buffered开头

缓冲流: 
                            字节流                  字符流
    输入流缓冲流      BufferedInputStream         BufferedReader
    输出缓冲流        BufferedOutputStream        BufferedWriter
2、缓冲流的优点

​ 内部自带数组,提高IO流的效率

3、字节缓冲流
1、字节输出缓冲流: BufferedOutputStream

(1)构造方法:

​ BufferedOutputStream(OutputStream out)

​ (缓冲流只是提供数组,来提高IO流的效率真的操作文件的是参数传入的基本流)

(2)普通方法:

BufferedOutputStream继承了OutputStream使用的还是OutputStream里面那些写数据的方法

public static void test01() throws IOException {
    // 1.创建缓冲流,传入基本流
    // FileOutputStream fos = new FileOutputStream("day10demo/abc/bos.txt");
    // BufferedOutputStream bos = new BufferedOutputStream(fos);
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day10demo/abc/bos.txt"));

    // 2.调用写数据的方法
    byte[] bytes = new byte[] {65, 66, 67, 68, 69};
    bos.write(bytes);

    // 3.关闭流
    bos.close();
}
2、字节输入缓冲流: BufferedInputStream

(1)构造方法:

​ BufferedInputStream(InputStream in):

​ (缓冲流只是提供数组,来提高IO流的效率真的操作文件的是参数传入的基本流)

(2)普通方法:

BufferedInputStream继承了InputStream,故使用的还是InputStream里面的那些读取数据的方法

public static void test02() throws IOException {
    // 1.创建字节输入缓冲流,传入基本流
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day10demo/abc/bos.txt"));

    // 2.调用方法读取数据
    int len;
    byte[] buf = new byte[1024];
    while ((len = bis.read(buf)) != -1) {
        System.out.println(new String(buf, 0, len));
    }

    // 3.关闭流
    bis.close(); // 关闭缓冲流的时候,会自动帮我们关闭基本流
}
4、字符缓冲流
1、字符输出缓冲流: BufferedWriter

(1)构造方法

BufferedWriter(Writer out) 需要传入一个基本流

(2)普通方法

​ BufferedWriter继承了Writer使用的是Writer里面写数据的方法

特有方法

写一个换行符 void newLine()     "\r\n"
1、字符输入缓冲流: BufferedReader

(1)构造方法

BufferedReader(Reader r) 需要传入一个基本流

(2)普通方法

​ BufferedReader继承了Reader,使用的是Reader里面读取数据的方法

特有方法

特有方法:String readLine() 返回读取到的那行数据
public static void main(String[] args) throws IOException {
    test01();
    // test02();
}

/*
    字符输入缓冲流: BufferedReader
        BufferedReader继承了Reader,使用的是Reader里面读取数据的方法
        BufferedReader构造方法:
            BufferedReader(Reader r) 需要传入一个基本流

            特有方法:String readLine() 返回读取到的那行数据
 */
public static void test02() throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("day10demo/abc/bw.txt"));

    /*
    int len;
    char[] chs = new char[1024];
    while ((len = br.read(chs)) != -1) {
        System.out.println(new String(chs, 0, len));
    }
    */

    // 特有方法:String readLine() 返回读取到的那行数据
    /*
    String line = br.readLine();
    System.out.println(line);

    line = br.readLine();
    System.out.println(line);

    line = br.readLine();
    System.out.println(line);

    line = br.readLine();
    System.out.println(line);
    */

    String line;
    while ((line = br.readLine()) != null) {//当当前行数为空时,返回值是null
        System.out.println(line);
    }

    br.close();
}

/*
    字符输出缓冲流: BufferedWriter
        BufferedWriter继承了Writer使用的是Writer里面写数据的方法
        BufferedWriter构造方法:
            BufferedWriter(Writer out) 需要传入一个基本流
            特有方法: 写一个换行符 void newLine()     (之前换行符表示为:"\r\n")
 */
public static void test01() throws IOException {
    // 1.创建字符输出缓冲流
    BufferedWriter bw = new BufferedWriter(new FileWriter("day10demo/abc/bw.txt"));
    // 2.写数据
    bw.newLine();
    bw.write("事实证明寒冷的天气可以使人年轻,张大爷今年80岁了,冻的像个孙子似的");
    bw.newLine();
    // 3.关闭流
    bw.close();
}

4、编码

5、字符转换流

操作字符时如何选择流?
    基本流:FileReader/FileWriter
    转换流:InputStreamReader/OutputStreamWriter

    如果不需要指定字符集使用基本流,
    如果需要指定字符集使用转换流
1、InputStreamReader转换流读字符数据
1、概念:

​ InputStreamReader,

​ (1)属于输入字符流,

​ (2)继承了Reader,使用Reader的那些读数据的方法。

2、构造方法
InputStreamReader(InputStream in) 使用默认的UTF-8
InputStreamReader(InputStream in, String charsetName) 使用指定的字符集

真正操作文件靠的参数的基本流,转换流负责将读取到的数据去查码表转成对应文字

3、作用

​ 可以指定编码来取文件的数据

// InputStreamReader(InputStream in) 使用默认的UTF-8
// InputStreamReader: 属于输入字符流,继承了Reader,使用Reader的那些都数据的方法
public static void test01() throws IOException {
    InputStreamReader isr = new InputStreamReader(new FileInputStream("day10demo/abc/china_utf8.txt"));

    int ch;
    while ((ch = isr.read()) != -1) {
        System.out.println((char)ch);
    }

    isr.close();
}
// InputStreamReader(InputStream in, String charsetName) 使用指定的字符集 gbk/GBK utf-8/UTF-8
public static void test02() throws IOException {
    InputStreamReader isr = new InputStreamReader(new FileInputStream("day10demo/abc/china_gbk.txt"), "gbk");//第二个参数填不存在的编码字符如"nba"则会报错

    int ch;
    while ((ch = isr.read()) != -1) {
        System.out.println((char)ch);
    }

    isr.close();
}
2、OutputStreamWriter转换流写字符数据
1、概念

​ OutputStreamWriter:

​ (1)属于字符输出流,

​ (2)继承了Writer使用Writer中的那些写数据方法

2、构造方法
OutputStreamWriter(OutputStream out) //创建一个使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName) //创建一个使用指定字符编码的																OutputStreamWriter

真正操作文件靠基本流.转换流负责查询码表

3、作用

​ 可以指定编码文本数据

// OutputStreamWriter(OutputStream out, String charsetName) 创建一个使用指定字符编码的OutputStreamWriter
public static void test02() throws IOException {
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day10demo/abc/osw_gbk.txt"), "GBK");

    osw.write("你不要乱来!");
    osw.close();
}

// OutputStreamWriter(OutputStream out) 创建一个使用默认字符编码的OutputStreamWriter
public static void test01() throws IOException {
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day10demo/abc/osw_utf8.txt"));

    osw.write("你不要乱来!");

    osw.close();
}
3、转换文件编码核心

使用指定的编码读取文件数据,再使用指定编码写数据

案例:将GBK编码的文本文件,转换为UTF-8编码的文本文件

步骤:
    1.创建一个InputStreamReader,指定字符集为GBK
    2.创建一个OutputSreamWriter,指定字符集为UTF-8
    3.循环读写
    4.关闭流
public static void main(String[] args) throws IOException {
    // 1.创建一个InputStreamReader,指定字符集为GBK
    InputStreamReader isr = new InputStreamReader(new FileInputStream("day10demo/abc/gbk.txt"), "gbk");
    // 2.创建一个OutputSreamWriter,指定字符集为UTF-8
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day10demo/abc/convertoutf-8.txt"));

    // 3.循环读写
    int len;
    char[] chs = new char[1024];
    while ((len = isr.read(chs)) != -1) {
        osw.write(chs, 0, len);
    }

    // 4.关闭流
    osw.close();
    isr.close();
}

6、序列化流与反序列化流

1、ObjectOutputStream对象字节输出流(序列化流)

1、序列化?

​ 将程序中的对象的数据保存到文件中

2、构造方法

ObjectOutputStream(OutputStream in) 需要传入一个基本流写数据到哪个文件

3、要被序列化的类需要实现serializable接口

(1)Serializable接口属于标记接口,内部任何内容都没有

(2)类在实现了Serializable接口后,类会自动拥有一个序列化号

4、在类中指定成员变量不序列化到文件的办法

​ 用transient或者static修饰。被这两个关键字修饰的成员变量不会被序列化。

5、该类的将对象写入文件的方法

void writeObject(Object obj)

6、对象序列化流将对象写入文件中步骤

1.定义个Person类
2.创建Person对象
3.创建序列化流ObjectOutputStream
4.调用方法将对象的数据写入文件中
5.关闭流
public static void main(String[] args) throws IOException {
    // 1.定义个Person类
    // 2.创建Person对象
    Person p1 = new Person("凤姐", 18);

    // 3.创建序列化流ObjectOutputStream
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10demo/abc/persons.txt"));

    // 4.调用方法将对象的数据写入文件中
    // void writeObject(Object obj)
    oos.writeObject(p1);

    // 5.关闭流
    oos.close();
}
2、ObjectInputStream对象字节输入流(反序列化流)

1、反序列化?

​ 将文件中对象的数据读取到程序中

2、构造方法

ObjectInputStream(InputStream in) 需要传入一个基本流读取哪个文件

3、该类的将对象写入文件的方法

public static void main(String[] args) throws IOException, ClassNotFoundException {
    // 1.创建反序列化流ObjectInputStream
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day10demo/abc/persons.txt"));
    // 2.调用readObject读取一个对象
    // Object obj = new Person("凤姐", 18);
    Object obj = ois.readObject();
    // 实际上走的是右边person对象的toString
    System.out.println(obj.toString()); // Person{name='凤姐', age=18}

    // 3.关闭流
    ois.close();
}
3、序列化号冲突的问题

1、什么是序列化流冲突问题

(1)有上述可知,类实现了Serializable接口后,类会自动拥有一个序列化号

(2)将该实现了Serializable接口后的类序列化到文件中,类的序列化号也会保存到文件中

(3)在使用对象反序列化流将对象取出来的时候,会对保存到文件中的列的序列化流进行验证,验证其与类中的序列化流是否一致。

(4)若一致,则读取成功

(5)若中途修改了类的内容,如添加、删改类的成员变量等,类的序列化号就发生改变。验证就会不一致,则读取失败,抛出异常(异常中会显示前后的序列化号)

2、如何避免、解决序列化流冲突的问题

在类中定义一个序列化号的成员变量,序列化号随机

​ 这样修改类也不会改变类的序列化号

public class Person implements Serializable {//实现Serializable接口
    public static final long serialVersionUID = 6668889999L;//在类中定义一个序列化号的成员变量
    private String name;
    private transient int age;
    // private double height;//修改类的内容
}    
4、序列化和反序列化集合
1、概念

​ 将集合序列化到文件

2、步骤:
1.定义一个集合
2.保存一些数据到集合中
3.将集合序列化到文件
4.读取文件中的集合数据(反序列化集合)
3、注意:
集合中的数据也要实现序列化接口
存储的是什么类型,取的就是什么类型
// 序列化集合
public static void test01() throws IOException {
    // 1.定义一个集合
    ArrayList<Person> list = new ArrayList<>();

    // 2.保存一些数据
    list.add(new Person("樱木花道", 18));
    list.add(new Person("流川枫", 19));
    list.add(new Person("赤木晴子", 16));
    list.add(new Person("仙道", 17));

    // 3.将集合序列化到文件
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day10demo/abc/glgs.txt"));
    oos.writeObject(list);
    oos.close();
}
// 4.读取文件中的集合数据(反序列化集合)
    public static void test02() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day10demo/abc/glgs.txt"));

        //虽然返回值是Object类型,但当初存入文件的是ArrayList<Person>类型,故可以用该类型进行接收
        // Object obj = ois.readObject();
        ArrayList<Person> list = (ArrayList<Person>) ois.readObject();
        for (Person p : list) {
            System.out.println(p);
        }
}

7、打印流

1、特点:

​ (1)只有输出方向,没有输入方向
​ (2)原样输出,写什么就打印什么

2、分类

​ 字节打印流:PrintStream
​ 字符打印流:PrintWriter(不常用)

3、PrintStream类
(1)构造方法
PrintStream(String fileName) 使用指定的文件名创建新的打印流,无需自动换行。
PrintStream(File file) 使用指定的文件创建一个新的打印流,而不需要自动换行。
PrintStream(OutputStream out) 创建一个新的打印流。
(2)普通方法
print(Xxx x) 不换行原样打印数据
println(Xxx x) 原样打印数据,并换行
public static void test01() throws FileNotFoundException {
        // 1.创建打印流
        PrintStream ps = new PrintStream("day10demo/abc/ps.txt");

        // 2.调用打印的方法
        // 不换行打印
        /*ps.print(100);
        ps.print('a');
        ps.print("嘎嘎");
        ps.print(true);*/

        // 换行打印
        ps.println(111);
        ps.println('号');
        ps.println("鸡鸡");
        ps.println(6.66);
        ps.println(false);

        ps.close();
    }
4、扩展了解打印输出语句sout
平时在代码的某些地方添加一些打印信息,开发的时候打印在控制台,而在项目部署的时候,打印到文件------>叫做"收集log信息"
// 扩展:System.out是一个打印流,往控制台打印
// 我们知道,类名能够调用Out,说明Out是static修饰的,out是一变量
System.out.println("ooooo");
System.out.print("111");
System.out.print("222");

// 我们可以给他换一个打印流,让他往指定位置来打印
PrintStream ps = new PrintStream("day10demo/abc/666.txt");
System.setOut(ps);//设置Out变量的方法setOut()

System.out.println("333");
System.out.println("444");

8、流的总结

[外链图片转存失败(img-h3VYBIsV-1564157618826)(E:\1a黑马java\黑马java\就业班\day10—\source\字节流总结.png)]

[外链图片转存失败(img-0KyHtZzE-1564157618830)(E:\1a黑马java\黑马java\就业班\day10—\source\字符流总结.png)]

rint(‘a’);
ps.print(“嘎嘎”);
ps.print(true);*/

    // 换行打印
    ps.println(111);
    ps.println('号');
    ps.println("鸡鸡");
    ps.println(6.66);
    ps.println(false);

    ps.close();
}



##### 4、扩展了解打印输出语句sout

 	平时在代码的某些地方添加一些打印信息,开发的时候打印在控制台,而在项目部署的时候,打印到文件------>叫做"收集log信息"

```java
// 扩展:System.out是一个打印流,往控制台打印
// 我们知道,类名能够调用Out,说明Out是static修饰的,out是一变量
System.out.println("ooooo");
System.out.print("111");
System.out.print("222");

// 我们可以给他换一个打印流,让他往指定位置来打印
PrintStream ps = new PrintStream("day10demo/abc/666.txt");
System.setOut(ps);//设置Out变量的方法setOut()

System.out.println("333");
System.out.println("444");

8、流的总结

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值