【Java SE进阶】Day09 字节流、字符流、I/O操作、属性集

一、I/O概述

1、输入输出

  • 输入:硬盘-->内存
  • 输出:内存-->内存

2、流

  • 字节流:一个字节等于8位
  • 字符流:一个字符=2个字节

二、字节流

1、概述

  • 以字节的方式读取/传输
  • 可以读取任意文件

2、字节输出流

  • OutputStream
  • 抽象类,是所有字节输出类的超类
  • 方法:
    • close() 
    • flush() :刷新并写出
    • write(byte[] b)
    • write(byte[] b, int off, int len) 
    • write(int b) :写入指定的字节,如97
  • 构造方法传递文件路径的两种形式      
  • 常见子类:
    • FileOutputStream
    • ObjectOutputStream
    • ……

  • 输出一个字节  
public class Demo01OutputStream {
    //字节输出流写入数据到文件【内存->硬盘】
    public static void main(String[] args) throws IOException {
        //声明异常,所有异常都是io包下的,
        // 只需要声明所有io异常的父类IOException
        FileOutputStream fos =new FileOutputStream("src\\com\\liujinhui\\Day1105Stream\\a.txt");//抛出异常,声明
        fos.write(97);//写一个字节到文件中
        fos.close();//关闭此流并释放与流相关的所有资源
    }

}
  • 输出多个字节 
public class Demo02FileOutputStream {
    public static void main(String[] args) throws IOException {
        //创建FileOutputStream对象,将数据目的地传入
        FileOutputStream fos=new FileOutputStream(new File("src\\com\\liujinhui\\Day1105Stream\\b.txt"));
        //对象调用方法write,把数据写入到文件中
        //想往文件中写100
        fos.write(49);
        fos.write(48);
        fos.write(48);

        /*
        * void write(byte[] b)
          将 b.length 个字节从指定 byte 数组写入此文件输出流中。
          一次写多个字节:
                    如果写的第一个字节是正数(0-127),显示的时候会查询ASCII码表
                    如果写的第一个字节是负数,那么第一个字节会和第二个字节,两个字节组成一个中文显示,查询默认码表(GBK)
        * */
        //byte[] bytes={65,66,67,68,69};//ABCDE
        byte[] bytes={65,66,67,68,69};
        fos.write(bytes);
        /* void write(byte[] b, int off, int len) :把字节数组的一部分写入到文件中
          将指定 byte 数组中从偏移量 off 【数组的开始索引】开始的 len 个字节写入此文件输出流。
          */
        fos.write(bytes,1,2);
        //写入字符串的方法
        /*
        *   可以使用String类中的方法,把字符串转化为字符数组
        *    byte[] getBytes(Charset charset)
          使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
        * */
        byte[] bytes2="你好".getBytes();//[-28, -67, -96, -27, -91, -67]
        //使用的UTF-8,三个字节是一个中文
        //GBK两个字节是一个中文
        System.out.println(Arrays.toString(bytes2));
        fos.write(bytes2);
        fos.close();
    }
}
  • 文件追加&续写
package com.liujinhui.Day1105Stream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 追加写/续写:使用FileOutputStream的两个参数的构造方法
*FileOutputStream(File file, boolean append)
          创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name, boolean append)
          创建一个向具有指定 name 的文件中写入数据的输出文件流。

      参数1:写入数据的目的地
      参数2:追加写开关,true就追加写数据,false就创建新文件,覆盖原来的文件,重新写数据

写换行:写换行符号
          windows:\r\n
          linux :/n
          mac:/r
* */
public class Demo03Append {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos=new FileOutputStream("src\\com\\liujinhui\\Day1105Stream\\c.txt",true);
        for (int i=0;i<10;i++){
            fos.write("你好".getBytes());
            fos.write("\r\n".getBytes());
        }
        fos.close();
    }
}

3、字节输入流

  • InputStream,所有字节输入流的父类
  • 常见子类 
    • read() :读一个字节,读取到文件末尾时读取完毕
    • read(byte[] b) 
    • read(byte[] b, int off, int len) 
    while ((len=fis.read())!=-1){
            System.out.print(len);
            System.out.println(len);
            System.out.print((char)len);//转换为对应字符
        }

  •  读取多个字节
package com.liujinhui.Day1105Stream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
/*
    字节输入流一次读取多个字节的方法:
*  int read(byte[] b)
          从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
 int read(byte[] b, int off, int len)
          从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
    明确:
        1.方法参数byte[] b的作用
        2.方法的返回值int是什么
    String类的构造方法:
            String(byte[] bytes)
          通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String
          String(byte[] bytes, int offset, int length)
          通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。
* */
public class Demo06MultiBitReadFileInput {
    public static void main(String[] args) throws IOException {
        //创建FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis=new FileInputStream("src\\com\\liujinhui\\Day1105Stream\\a.txt");
        //使用read读取文件
        byte[] bytes=new byte[2];
        int len=fis.read(bytes);
        System.out.println(len);
        System.out.println(Arrays.toString(bytes));//Arrays的toString方法
        System.out.println(new String(bytes));//String的构造 ab

        len=fis.read(bytes);//2
        System.out.println(len);//读取的字节的个数
        System.out.println(new String(bytes));//String的构造   ih

        len=fis.read(bytes);//-1
        System.out.println(len);//读取的字节的个数
        System.out.println(new String(bytes));//String的构造  ih
        //释放资源
        fis.close();
    }
}

  •  优化:
package com.liujinhui.Day1105Stream;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

public class Demo06MultiBitReadFileInput {
    public static void main(String[] args) throws IOException {
        //创建FileInputStream对象,构造方法中绑定要读取的数据源
        FileInputStream fis=new FileInputStream("src\\com\\liujinhui\\Day1105Stream\\a.txt");
        //使用read读取文件
        byte[] bytes=new byte[1024];
        int len=0;//记录每次读取的有效字节个数
        //读取事一个重复的过程,可以使用循环优化
        /*
        * 不知道文件中有多少字节,所以使用while循环
        * while循环结束的条件:读取到-1结束
        * */
        while((len=fis.read(bytes))!=-1){
            System.out.println(new String(bytes,0,8));//读取从0开始的7个有效字符串
            //使用1个参数的String构造方法,如果一次读取的byte数组初始化过长,会产生很多空格
        }
        //释放资源
        fis.close();
    }
}
  • 练习:从A文件将内容读入,并写出到B文件 中

package com.liujinhui.Day1105Stream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/*
*     文件复制练习:一读一写
*     明确:
*           数据源:D:\\a.bmp
*           数据目的地:E:\\a.bmp
*     文件复制的步骤
*               1.创建输入流对象,绑定数据源
*               2.创建字节输出流对象,构造方法中绑定目的地
*               3.使用输入流中的read读
*               4.使用输出流中的write写
*               5.释放资源
* */
public class Demo07FileCopy {
    public static void main(String[] args) throws IOException {
        //1.创建输入流对象,绑定数据源
        FileInputStream fis=new FileInputStream("d:\\a.bmp");
        //2.创建字节输出流对象,构造方法中绑定目的地
        FileOutputStream fos =new FileOutputStream("e:\\b.bmp");
        /*
        * 3.使用输入流中的read读
*          4.使用输出流中的write写
        * */
        int len=0;
        //一次读取一个字节,写入一个字节
        while((len=fis.read())!=-1){
            fos.write(len);
        }
        //释放资源(先关写的,再关读的,如果写完了,肯定读完了)
        fos.close();
        fis.close();
    }
}

三、字符流

1、字节流读取中文问题

package com.liujinhui.Day1105Stream;
/*
    问题:使用字节流读取中文文件
    1个中文
            GBK:占用2个字节
            UTF-8:占用3个字节
* */
import java.io.FileInputStream;
import java.io.IOException;
public class Demo08GBKUTF {
    public static void main(String[] args) throws IOException {
        FileInputStream fis=new FileInputStream("src\\com\\liujinhui\\Day1105Stream\\c.txt");//UTF-8 占用3字节
        int len=0;
        while((len=fis.read())!=-1){
            System.out.println(len);//6个数
            //System.out.println((char)len);//产生乱码
        }
        fis.close();
    }
}

2、字符输入流

  • Reader类,是所有字符输入流的超类
package com.liujinhui.Day1105Stream;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/*
    java.io.Reader:字符输入流,是最顶层父类,定义了一些共性的成员方法,是一个抽象类
    共性的成员方法:
             int read() 读取单个字符并返回
             int read(char[] cbuf) 一次读取多个字符,将字符读入数组
             abstract  void close() 关闭该流并释放与之关联的所有资源
     抽象类的常见子类:
               直接已知子类:
               BufferedReader, CharArrayReader, FilterReader, InputStreamReader【其下面的子类FileReader用来读取字符文件的便捷类】, PipedReader管道流, StringReader
       java.io.FileReader文件字符输入流 extends java.io.InputStreamReader  extends java.io.Reader多重继承
       作用:把硬盘文件中的数据以字符的方式读入内存中

       构造方法:
               FileReader(File file)
          在给定从中读取数据的 File 的情况下创建一个新 FileReader。
                FileReader(String fileName)
          在给定从中读取数据的文件名的情况下创建一个新 FileReader

         构造方法的作用:
                1.创建一个FileReader对象
                2.把FileReader对象指向要读取的文件
         FileReader字符输入流的使用步骤:
            1.创建FileReader对象,构造方法中绑定读取的数据源
            2.使用FileReader中的方法read读取文件
            3.释放资源
* */
public class Demo09Reader {
    public static void main(String[] args) throws IOException {
        //1.创建FileReader对象,构造方法中绑定读取的数据源
        FileReader fr=new FileReader("src\\com\\liujinhui\\Day1105Stream\\c.txt");
        //2.使用FileReader中的方法read读取文件
        /*int len=0;
        //读取单个
        while((len=fr.read())!=-1){
            System.out.print((char) len);
        }*/
        //使用数组缓冲读取多个字符
        char[] cs=new char[1024];//存储到的多个字符
        int lens=0;//记录的是每次读取的有效字符个数
        /* 把字符数组转换为字符串
            String(char[] value)
          分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。
          把字符数组的一部分转换为字符串
            String(char[] value, int offset, int count)
          分配一个新的 String,它包含取自字符数组参数一个子数组的字符。
        * */
        while((lens=fr.read(cs))!=-1){
            System.out.println(new String(cs,0,lens));
        }
    }
}

3、字符输出流

package com.liujinhui.Day1105Stream;
import java.io.FileWriter;
import java.io.IOException;
/*
    java.io.Writer:字符输出流,是所有字符输出流的最顶层父类,是一个抽象类

    成员方法:
            abstract  void close()
                      关闭此流,但要先刷新它。
            abstract  void flush()
                      刷新该流的缓冲。
             void write(char[] cbuf)
                      写入字符数组。
            abstract  void write(char[] cbuf, int off, int len)
                      写入字符数组的某一部分。
             void write(int c)
                      写入单个字符。
      子类:BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter
       java.io.Writer
      继承者 java.io.OutputStreamWriter
          继承者 java.io.FileWriter
      java.io.FileWriter文件字符输出流
      作用:把内存中的字符数据写入到文件中
      构造方法:
            FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象,写入数据的目的地,是一个文件的路径
            FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象
       构造方法的作用:
            1.创建FileWriter对象
            2.根据构造方法中传递的文件/文件路径,创建文件
            3.把FileWriter对象指向创建好的文件
        使用步骤:
            1.创建一个FileWriter对象,构造方法中绑定要写入数据的目的地
            2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
            3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
            4.释放资源(会把内存缓冲区中的数据刷新到文件中)
* */
public class Demo10Writer {
    public static void main(String[] args) throws IOException {
        //1.创建一个FileWriter对象,构造方法中绑定要写入数据的目的地
        FileWriter fw=new FileWriter("src\\com\\liujinhui\\Day1105Stream\\d.txt");
        //2.使用FileWriter中的方法write,把数据写入到内存缓冲区中(字符转换为字节的过程)
        fw.write(97);//不关闭,文件中没有数据【write把字符转化为字节】
        //3.使用FileWriter中的方法flush,把内存缓冲区的数据,刷新到文件中
        fw.flush();
        //4.释放资源(会把内存缓冲区中的数据刷新到文件中)
        fw.close();
    }
}
  • 其他方法(直接写入字符串)
package com.liujinhui.Day1105Stream;
import java.io.FileWriter;
import java.io.IOException;
/*
    字符输出流写数据的其他方法
         void write(char[] cbuf)
                  写入字符数组。
        abstract  void write(char[] cbuf, int off, int len)
                  写入字符数组的某一部分。
         void write(int c)
                  写入单个字符。
         void write(String str)
                  写入字符串。
         void write(String str, int off, int len)
                  写入字符串的某一部分。
* */
public class Demo12WriterOther {
    public static void main(String[] args) throws IOException {
        FileWriter fw =new FileWriter("src\\com\\liujinhui\\Day1105Stream\\f.txt");
        char[] cs={'a','c','b','a','h'};
        fw.write(cs);//acbah
        //写字符数组的一部分
        fw.write(cs,1,3);//cba
        //写字符串
        fw.write("刘金辉");//刘金辉
        fw.write("黑马程序员",2,3);//程序员
        fw.close();
    }
}
  • 续写换行同字节输出流

四、I/O异常的处理

1、try_catch_finally

2、JDK7(try加括号自动释放)和JDK9(多变量分号分隔)

package com.liujinhui.Day1105Stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/*
    jdk9新特性
    在try前定义流对象
    在try后面的()中可以直接引入流对象的变量名
    在try的代码执行完毕之后,流对象也可以释放掉,不用谢finally
    格式:
        A a=new A();
        B b=new B();
        try(a,b){
        .......}
        catch(){
        }
* */
public class Demo16JDK9Exception {
    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream fis=new FileInputStream("d:\\a.bmp");
        //2.创建字节输出流对象,构造方法中绑定目的地
        FileOutputStream fos =new FileOutputStream("e:\\b.bmp");
        try(fis;fos) {
            long s = System.currentTimeMillis();
            //使用数组缓冲读取多个字节,写入多个字节
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
        }
        catch(IOException e){
            System.out.println(e);
        }
        long e=System.currentTimeMillis();
        System.out.println("复制文件共耗时"+(e-s)+"毫秒");
        //fos.write(97);//不能再写,流已经被关闭
    }
}

五、属性集

1、概述

package com.liujinhui.Day1105Stream;
import java.util.Properties;
import java.util.Set;
/*
    java.util.Properties集合 extends java.util.Properties implements Map<k,v>
    Properties类表示了一个持久的属性集,Properties可保存在流中或从流中加载
    Properties集合是一个唯一和IO流相结合的集合
        可以使用Properties集合中的方法store把集合中的临时数据,持久化写入到硬盘中存储
        可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
    属性列表中的每个键和对应的值都是一个字符串:
        Properties集合是一个双列集合,key和value默认都是字符串,无需写泛型
* */
public class Demo17Properties {
    public static void main(String[] args) {
        show01();
    }
    /*
    *   使用Properties集合存储数据,遍历取出Properties集合中的数据
    *   Properties集合是一个双列集合,key和value默认都是字符串
    *   Properties有一些操作字符串的特有方法
    *       Object setProperty(String key, String value)
            调用 Hashtable 的方法 put。 【map中的put方法】
            String getProperty(String key, String defaultValue) 【通过key找value值】
            用指定的键在属性列表中搜索属性。 【map集合中的get方法】
            Set<String> stringPropertyNames() 【map集合中的keySet()方法】
            返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键。
    *
    * */
    private static void show01() {
        //1.创建Properties集合对象
        Properties prop=new Properties();
        //2.使用setProperty方法
        prop.setProperty("赵丽颖","168");
        prop.setProperty("迪丽热巴","165");
        prop.put("欧阳娜娜",166);//可以用但不推荐,设置错的话取不出来
        //使用stringPropertyNames方法,把集合中的键取出存储到set集合中
        Set<String> set=prop.stringPropertyNames();
        //遍历键,使用getProperty,通过key获取value
        for (String key:set){
            System.out.println(prop.getProperty(key));
        }
    }

}

2、方法store

package com.liujinhui.Day1105Stream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/*
    store方法,把集合中的临时数据,持久化写入硬盘存储
     void store(OutputStream out, String comments) 【传递字节输出流,不能写中文】
          以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
     void store(Writer writer, String comments) 【传递字符输出流,可以写中文】
          以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。
     参数:
            String comments---注释,用来解释保存的文件是来做啥的,不能用中文,默认是Unicode编码,系统是GBK
            一般使用空字符串
     使用步骤:
        1.创建Properties集合对象,添加数据
        2.创建字节输出流/字符输出流对象,构造方法中绑定输出数据的目的地
        3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
        4.释放资源
* */
public class Demo18PropertiesStore {
    public static void main(String[] args) throws IOException{
        show03();
    }
    private static void show03() throws IOException{
        //使用字节流
        //1.创建Properties集合对象,添加数据
        Properties prop=new Properties();
        //2.使用setProperty方法
        prop.setProperty("赵丽颖","168");
        prop.setProperty("迪丽热巴","165");
        //2.创建字节输出流,但是字节流显示的是乱码,不能保存中文
        prop.store(new FileOutputStream("src\\com\\liujinhui\\Day1105Stream\\r.txt"),"new save");
    }
    private static void show02() throws IOException {
        //1.创建Properties集合对象,添加数据
        Properties prop=new Properties();
        //2.使用setProperty方法
        prop.setProperty("赵丽颖","168");
        prop.setProperty("迪丽热巴","165");
        //2.创建字节输出流/字符输出流对象,构造方法中绑定输出数据的目的地
        FileWriter fw=new FileWriter("src\\com\\liujinhui\\Day1105Stream\\h.txt");
        //3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
        prop.store(fw,"save data");
        //4.释放资源
        fw.close();
    }
}

3、方法load

package com.liujinhui.Day1105Stream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
/*
    void load(InputStream inStream)
          从输入流中读取属性列表(键和元素对)。
    void load(Reader reader)
          按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
     参数:
        -InputStream inStream :字节输入流,不能读取含有中文的键值对
        -Reader reader:字符输入流,可以读取含有中文的键值对
    使用步骤:
        1.创建Properties集合对象
        2.使用Properties集合对象中的方法load读取键值对文件
        3.遍历Properties集合对象集合
    注意:
        1.存储键值对的文件中,键和值的连接符可以使用- 、空格或其他符号
        2.存储键值对的文件中,使用#被注释的键值对,不会再被读取
        3.存储的文件中,默认是字符串,不用再加引号
* */
public class Demo19Load {
    public static void main(String[] args) throws IOException{
        show03();
    }
    private static void show03() throws IOException {
        //1.创建Properties集合对象
        Properties prop=new Properties();
        //2.使用Properties集合对象中的方法load读取键值对文件
        prop.load(new FileReader("src\\com\\liujinhui\\Day1105Stream\\h.txt"));
        //3.遍历Properties对象集合
        Set<String> set=prop.stringPropertyNames();
        for (String key:set){
            String value=prop.getProperty(key);
            System.out.println(key+"-"+value);
        }
    }
}

 

posted @ 2021-05-30 22:43  哥们要飞  阅读(48)  评论(0编辑  收藏  举报