黑马程序员技术交流社区

标题: <石家庄校区>Day09--10 [打印本页]

作者: yangxiaoqiang    时间: 2018-11-26 15:49
标题: <石家庄校区>Day09--10
day09 字节流 字符流 Properties
IO流:输入(Input)输出(Output)流 流:数据流
IO流的分类:
    字节流 (读写字节: byte, 可以读写所有类型的文件, 包括视频, 图片, 音频, 文本等)
        字节输入流: java.io.InputStream 抽象类
        字节输出流: java.io.OutputStream 抽象类
    字符流 (读写字符: char, String, 只能读写文本文件)
        字符输入流: java.io.Reader 抽象类
        字符输出流: java.io.Writer 抽象类
字节输出流:
java.io.OutputStream抽象类: 字节输出流 (顶层类)
// 成员方法
    void close() :释放资源
    void flush() :刷新缓冲区(对于字节流来说没有作用)
// 写字节的成员方法
    abstract void write(int b): 一次写一个字节 (参数int便于传递byte的整数不用强转)
    void write(byte[] b): 一次写一个字节数组
    void write(byte[] b, int offset, int len): 一次写一个字节数组的一部分
java.io.FileOutputStream类: 文件字节输出流 (向文件写数据)
    // 构造方法
    FileOutputStream(String name): 通过文件路径创建文件字节输出流
    FileOutputStream(File file): 通过File对象创建文件字节输出流
构造方法的作用:
        1. 创建一个FileOutputStream对象
        2. 根据构造方法传递的路径, 在磁盘上创建一个空文件 ("如果文件存在则会清空数据")
        3. 将创建的FileOutputStream对象指向这个磁盘上的文件
java.io.FileOutputStream类: 文件字节输出流 (向文件写数据)
    void write(byte[] b): 一次写一个字节数组
    void write(byte[] b, int off, int len): 一次写一个字节数组的一部分
java.lang.String类:
    byte[] getBytes(): 使用平台的默认字符集将此String编码为byte数组

写数据的原理:
    Java程序 -> JVM虚拟机 -> OS操作系统 -> OS调用写数据的方法 -> 将数据写入文件
FileOutputStream fos = new FileOutputStream("模块名\\文件名.txt");
    fos.write(97);
    fos.write("你好".getBytes())
    fos.close();

续写,换行
java.io.FileOutputStream类: 文件字节输出流
    // 带有 续写 功能的构造方法, 不会清空文件
    FileOutputStream(String name, boolean append): 通过文件路径创建流, true可以续写
    FileOutputStream(File file, boolean append): 通过File对象创建流, true可以续写
换行符:
    Windows系统: "\r\n"
    Linux系统: "\n"
    MacOS系统: "\r"

字节输入流:
java.io.InputStream抽象类: 字节输入流 (顶层类)
    // 常用成员方法
    void close(): 释放资源
    // 读数据的方法
    int read(): 一次读一个字节
        读到文件末尾返回-1 (返回int也是为了代码编写方便)
    int read(byte[] b): 一次读一个字节数组
        读到的字节存放在参数中的字节数组中, 返回int值是本次读到的字节的个数. 读到文件末尾返回-1   
java.io.FileInputStream类: 文件字节输入流
    // 构造方法
    FileInputStream(String name): 使用文件路径创建文件字节输入流
    FileInputStream(File file): 使用File对象创建文件字节输入流
    构造方法的作用:
        1. 创建FileInputStream对象
        2. 将FileInputStream对象指向磁盘上的文件

Java程序从文件读取数据的原理:
    Java程序 -> JVM虚拟机 -> OS(操作系统) -> OS调用读取的方法 -> 读取磁盘文件数据
java.io.InputStream抽象类: 字节输入流 (顶层类)
    int read(): 一次读一个字节
        读到文件末尾返回-1 (返回int也是为了代码编写方便)
实例:
FileInputStream fis = new FileInputStream("模块名\\文件名");
    // 一次读一个字节:
    int by;   // int变量用来存储每次读到的数据
    while (   (  by = fis.read()  ) != -1    ) {
        System.out.print((char)by);  // 不要换行, 文件中自带换行的byte
    }
    fis.close();
java.io.InputStream抽象类: 字节输入流 (顶层类)
    int read(byte[] b): 一次读一个字节数组
        参数 byte[] b 作用: 存储每次读到的字节, 起到缓冲作用
        返回值作用: 每次读到的字节个数, 读到文件末尾返回-1
// 示例代码
FileInputStream fis = new FileInputStream("模块名\\文件名");
byte[] bytes = new byte[1024];  // 定义字节数组, 用于保存每次读取到的数据
int len;                        // 定义int变量, 用于保存每次读取到的长度
while ((len = fis.read(bytes)) != -1) {
    String s = new String(bytes, 0, len); // 将读取到的字节转换为字符串, 读到多少个就转换多少个
    System.out.print(s);
}
fis.close(); // 释放资源

字符流:
注意: 字符流只能读写"文本文件"
java.io.Reader抽象类: 字符输入流 (顶层)
    // 常用成员方法
    void close() :关闭此流并释放与此流相关联的任何系统资源
    // 读
    int read(): 一次读一个字符char, 返回读到的字符.
        读到文件末尾返回-1  (返回int为了代码编写方便)
    int read(char[] cbuf): 一次读取一个字符数组char[]
        返回读取的字符个数. 读到文件末尾返回-1   
java.io.FileReader类: 文件字符输入流
    // 构造方法
    FileReader(File file): 根据File对象创建文件字符输入流
    FileReader(String fileName): 根据File对象创建文件字符输入流
    构造方法的作用:
        1. 创建FileReader对象
        2. 将FileReader对象指向磁盘上的文件

字符输入流:
java.io.Reader抽象类: 字符输入流 (顶层)
    int read(): 一次读一个字符char, 返回读到的字符.
        读到文件末尾返回-1  (返回int为了代码编写方便)
    int read(char[] cbuf): 一次读取一个字符数组char[]
        返回读取的字符个数. 读到文件末尾返回-1   
java.lang.String类:
    String(char[] value): 将char数组转换为String
    String(char[] value, int offset, int count): 将char数组的一部分转换为String

字符输出流:
java.io.Writer抽象类: 字符输出流 (顶层类)   'a''b'  缓冲区    97 98
    // 常用成员方法
    abstract void close(): 刷新缓冲区并释放资源
    abstract void flush() :刷新缓冲区
java.io.FileWriter类: 文件字符输出流
    // 构造方法
    FileWriter(File file): 通过File对象创建文件字符输出流
    FileWriter(String fileName): 通过文件路径创建文件字符输出流
    作用:
        1. 创建FileWriter对象
        2. 根据构造方法中的路径, 在磁盘上创建文件 ("如果文件已存在, 则清空文件内容")
        3. 将FileWriter对象指向磁盘上的文件

IO异常处理:
IO流的标准格式:
    FileWriter fw = null;
    try {
        //IO流对象的创建, 操作等代码
        fw = new FileWriter("d:\\09_IOAndProperties\\g.txt", true);
        for (int i = 0; i <10 ; i++) {
            fw.write("HelloWorld"+i+"\r\n");
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        // 释放资源
        if(fw != null){
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

JDK 7 增加的 "try-with-resource"
    省略了 finally, 可自动释放资源

    // 格式
    try (创建流对象语句,如果多个,使用';'隔开) {
        // 读写数据   
    } catch (IOException e) {
        e.printStackTrace();   
    }
// JDK 9 的格式适用于定义方法时, 通过参数传递流对象
public static void method(FileWriter fw, FileReader fr) {
    try (fw; fr) {
        // IO操作
        int ch = fr.read();
        fw.write(ch);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Properties集合:
Properties双列集合:
    键和值都是 String 类型
java.util.Properties类: 属性集, 属于Map的双列集合, 继承自Hashtable
    // 构造方法
    Properties(): 创建一个Properties集合
    // 可以使用Map接口中的方法
    // 特有成员方法
    Object setProperty(String key, String value): 保存/替换键值对
    String getProperty(String key): 通过键获取值. 键不存在返回null
    Set<String> stringPropertyNames(): 返回键的集合
    void store(OutputStream out, String comments): 将集合用字节流写入文件(不能中文),并写入注释
    void store(Writer writer, String comments): 将集合用字符流写入文件(可以中文),并写入注释
    void load(InputStream inStream): 从配置文件中通过字节流加载数据到Properties集合(不能中文)
    void load(Reader reader): 从配置文件中通过字符流加载数据到Properties集合(可以中文)

day10 缓冲流 转换流 序列化流 打印流

字节缓冲流
    |_ BufferedInputStream     # 缓冲字节输入流
    |_ BufferedOutputStream    # 缓冲字节输出流
字符缓冲流
    |_ BufferedReader          # 缓冲字符输入流
    |_ BufferedWriter          # 缓冲字符输出流   
java.io.BufferedOutputStream类: 缓冲字节输出流

缓冲字节输出流:BufferedOutputStream
java.io.BufferedOutputStream类: 缓冲字节输出流
    // 构造方法
    BufferedOutputStream(OutputStream out): 使用基本流创建一个缓冲字节输出流
    BufferedOutputStream(OutputStream out, int size): 使用基本流创建一个缓冲字节输出流, 设置缓冲区大小   
BufferedOutputStream使用步骤:
    1.创建FileOutputStream对象, 构造方法中绑定要输出的目的地
    2.创建BufferedOutputStream对象, 构造方法中传递FileOutputStream对象
    3.使用BufferedOutputStream对象中的方法 write(), 把数据写入到内部缓冲区中
    4.使用BufferedOutputStream对象中的方法 flush(), 把内部缓冲区中的数据,刷新到文件中
    5.释放资源(会先调用flush方法刷新数据, 第4步可以省略)

缓冲字节输入流:BufferedlnputStream
java.io.BufferedInputStream类: 缓冲字节输入流
    // 构造方法
    BufferedInputStream(InputStream in): 使用基本流创建一个缓冲字节输入流
    BufferedInputStream(InputStream in, int size): 使用基本流创建一个缓冲字节输入流, 设置缓冲区大小   
使用步骤:
    1.创建FileInputStream对象, 构造方法中绑定要读取的数据源
    2.创建BufferedInputStream对象, 构造方法中传递FileInputStream对象
    3.使用BufferedInputStream对象中的方法 read(), 读取文件
    4.释放资源 close()
     // 实例
    FileInputStream fis = new FileInputStream("文件路径");
    BufferedInputStream bis = new BufferedInputStream(fis);
    byte[] bytes = new byte[1024];
    int len;
    while ((len = bis.read(bytes)) != -1) {
        System.out.println(new String(bytes, 0, len));
    }
    bis.close();

缓冲字符输出流:BufferedWriter

java.io.BufferedWriter类:
    // 构造方法
    BufferedWriter(Writer out): 使用基本流创建一个缓冲字符输出流
    BufferedWriter(Writer out, int size): 使用基本流创建一个缓冲字符输出流, 设置缓冲区大小
    // 特有方法
    void newLine(): 写入一个换行符, 换行符自动根据当前系统确定

缓冲字符输入流:BufferedReader
java.io.BufferedReader类: 缓冲字符输入流
    // 构造方法
    BufferedReader(Reader in): 使用基本流创建一个缓冲字符输入流
    BufferedReader(Reader in, int size): 使用基本流创建一个缓冲字符输入流, 设置缓冲区大小
    // 特有方法
    String readLine(): 一次读一行字符串, "不包含换行符". 读到文件末尾返回null

字符编码和字符集:
编码: 字符 -> 字节  'a' -> 97
解码: 字节 -> 字符  97 -> 'a'
编码表: 字符和二进制数字的对应规则
字符集和编码表: 字符集包含编码表
    ASCII字符集
        ASCII编码表
        ASCII扩展编码表
    ISO-8859-1字符集: Tomcat Web服务器程序
        Latin-1: 拉丁字符. 没有中文. 每个字符由1个byte组成
    GB字符集
        GB2312编码表: 每个字符由2个byte组成
        GBK编码表: 每个字符由2个byte组成
        GB18030编码表: 每个字符由1, 2, 4个byte组成
    Unicode字符集
        UTF-8: ASCII字符占1个byte, 拉丁字符占2个byte, 中文占3个byte, Unicode辅助字符占4个byte
        UTF-16
        UTF-32
    ANSI: 表示使用系统默认编码表

java.io.Reader
    |_ InputStreamReader: 转换字符输入流      byte --查指定码表--> char, char[], String
        |_ FileReader                       byte --查UTF-8码表--> char
java.io.Writer
    |_ OutputStreamWriter: 转换字符输出流      char, char[], String --查指定码表--> byte
        |_ FileWriter                        char --查UTF-8码表--> byte

OutputStreamWriter类:
java.io.OutputStreamWriter类: 输出转换流. 字符流通往字节流的桥梁
    // 构造方法
    OutputStreamWriter(OutputStream out): 使用默认编码表创建转换流
    OutputStreamWriter(OutputStream out, String charsetName): 使用指定编码表创建转换流   
// 使用默认UTF-8
OutputStreamWriter o = new OutputStreamWriter(new FileOutputStream("a.txt"));
o.write("dsfdsfdsaf")
// 使用指定的GBK
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"), "GBK");
        osw.write("你") -> 查"GBK"码表 -> -1,-2 -> FileOutputStream -> a.txt文件
         写数据: 字符流 --------------------------> 字节流

InputSreamReader类:
java.io.InputStreamReader类: 输入转换流. 字节流通往字符流的桥梁
    // 构造方法
    InputStreamReader(InputStream in): 使用默认编码表创建转换流
    InputStreamReader(InputStream in, String charsetName): 使用指定编码表创建转换流   
// 使用默认UTF-8
InputStreamReader r = new InputStreamReader(new FileInputStream("a.txt"));
// 使用指定的GBK
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"), "GBK");
     '你' <- 查"GBK"码表 <- isr.read() <- -1,-2 <- FileInputStream <- a.txt文件
                         读数据: 字符流 <---------- 字节流   

序列化(对象流)
序列化: 内存中的对象转换为字节序列, 以流的方式写入到磁盘的文件中
    对象 -> 字节
反序列化: 磁盘文件中的字节序列, 以流的方式读取到内存中变成对象
    字节 -> 对象
通过序列化流, 我们可以将内存中的数据方便的存储到磁盘上, 下次程序启动后也能从磁盘读取恢复之前的对象状态
OutputStream
    |_ ObjectOutputStream类: 对象字节输出流
InputStream
    |_ ObjectInputStream类: 对象字节输入流

ObiectOutputStream:字节输出流
java.io.ObjectOutputStream类: 对象字节输出流
    // 构造方法
    ObjectOutputStream(OutputStream out)
    // 特有成员方法
    void writeObject(Object obj): 将对象写出   
// 创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.txt"));
// 写对象
Student s = new Student("小美女", 18);
oos.writeObject(s);
// 释放资源
oos.close();
注意:
    被读写的对象的类必须实现"java.io.Serializable"接口, 否则会抛出"NotSerializableException"

ObjectlnputStream:字节写入流
java.io.ObjectInputStream类: 对象字节输入流
    // 构造方法
    ObjectInputStream(InputStream in)
    // 特有成员方法
    Object readObject(): 读取对象   
// 创建对象输入流
ObjectInputStream oos = new ObjectInputStream(new FileInputStream("student.txt"));
// 读对象
Object o = oos.readObject();
Student s = (Student)o;
// 将读取到的对象强转为集合
        ArrayList<Person> list2 = (ArrayList<Person>)o;
// 遍历集合, 打印元素
        for (Person person : list2) {
            System.out.println(person);
        }
// 释放资源
oos.close();

transient瞬态关键字:避免属性序列化
static 修饰的成员变量属于类不属于对象, 所以不能序列化
transient 修饰的成员变量, 不能被序列化


transient 应用场景:
    如果对象的某个属性不希望被序列化, 可以使用 transient 修饰, 这样就不会被对象流写到文件中

InvalidClassException异常:
IDEA设置生成序列版本号:
Setting -> Editor -> Inspections -> Java -> Serialization issues -> 勾选Serializable class without 'serialVersionUID'

打印流PrintStream
PrintStream特点:
    1. 只有输出流, 没有输入流
    2. PrintStream不会抛出IOException
    3. 有特殊方法 print(), println(), 可以输出任意类型的值, 原样输出
java.io.PrintStream类: 字节打印流
    // 构造方法
    PrintStream(File file): 创建字节打印流, 输出到一个文件
    PrintStream(OutputStream out): 创建字节打印流, 输出到一个字节输出流
    PrintStream(String fileName): 创建字节打印流, 输出到一个文件路径   
注意事项:
    如果用 write(97) 方法, 会查编码表   97 -> a
    如果用 print(97), println(97), 则原样输出  97 int -> '9''7' -> byte -> 文件 97
    System.out.println();
    PrintStream out;   
java.lang.System类:
    // 静态方法
    static void setOut(PrintStream out): 设置System.out的输出目的地为参数的打印流







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2