IO流

流的概念

内存与存储设备之间传输数据的通道

流的分类

按方向

  • 输入流:将<存储设备>中的内容读到<内存>中 文件 --> 程序
  • 输出流:将<内存>中的内容写到<存储设备>中 程序 --> 文件

按单位

  • 字节流:以字节为单位,可以读写所有数据
  • 字符流:以字符为单位,只能读写文本数据

按功能

  • 节点流:具有实际传输数据的读写功能
  • 过滤流:在节点流的基础之上增强功能

字节流

字节流的父类是两个抽象类,抽象类不能实例化,让子类去继承它,实例化它的子类

// InputStream 字节输入流:表示字节输入流的所有类的超类 
public int read(){}  //  从输入流中读取数据的下一个字节,返回 0 到 255 范围内的 int 字节值,读到最后返回-1
public int read(byte[] b){} //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中,返回读入缓冲区的总字节数,读到最后返回-1
public int read(byte[] b, int off, int len){} //将输入流中最多len个数据字节读入byte数组,从b[off]开始

// OutputStream 字节输出流:  表示字节输出流的所有类的超类
public void write(int b){} // 将指定的字节写入此输出流
public void write(byte[] b){} //  将b.length个字节从指定的 byte 数组写入此输出流
public void write(byte[] b, int off, int len){} // 将指定 byte 数组中从off开始的 len 个字节写入此输出流

文件字节流

文件输入流

 public static void main(String[] args) throws Exception{
        // 1 创建FileInputStream 并指定已经存在的文件的路径
        FileInputStream fis = new FileInputStream("d:\\FileTest.txt");
        //d:\\FileTest.txt内容 ABCDEFG
        // 2 读取文件
        // 2.1单字节读取
        int data = 0;   
        while((data = fis.read()) != -1){  // data是相应的ascii值  int类型
            System.out.println((char)data); 
        }
        // 2.2 一次读取多个字节
        byte[] buf = new byte[3]; // 大小为3的缓存区

        int count = fis.read(buf); // 一次读3个
        System.out.println(new String(buf));
        System.out.println(count);

        int count2 = fis.read(buf); // 再读3个
        System.out.println(new String(buf));
        System.out.println(count2);

       //  上述优化后
        int count1 = 0;              //read()返回读入缓冲区的总字节数 
        while((count1 = fis.read(buf)) != -1){              //ABC
            System.out.println(new String(buf, 0, count1)); //DEF
        }                                                   //G

        // 3 关闭
        fis.close();
    }

文件输出流

    public static void main(String[] args) throws Exception{
        // 1 创建文件字节输出流
        FileOutputStream fos = new FileOutputStream("d:\\abc.txt", true);
        // 如果文件不存在,自动创建该文件,true表示如果文件存在则不覆盖,追加内容,
        // 2 写入文件
        fos.write(97); // a的ascii值,会自动写入字符 a
        fos.write('b');
        fos.write('c');
        String string = "hello world";
        fos.write(string.getBytes());
        // 3 关闭
        fos.close();
    }

文件复制案例

    public static void main(String[] args) throws IOException {
        // 1 创建流
        // 1.1 文件字节输入流
        FileInputStream fis = new FileInputStream("d:\\abc.txt");// jpg同理
        // 1.2 文件字节输出流
        FileOutputStream fos = new FileOutputStream("d:\\File.txt");
        // 2 边读边写
        byte[] buf = new byte[1024];
        int count = 0;
        while((count = fis.read(buf)) != -1){
            fos.write(buf, 0, count);
        }
        // 3 关闭
        fis.close();
        fos.close();
    }

字节缓冲流

缓冲流:BufferedInputStream/ BufferedOutputStream

  • 提高IO效率,减少访问磁盘次数
  • 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close也能将缓冲区的内容写入文件中
    // 使用字节缓冲流读取文件
    public static void main(String[] args) throws Exception{
        // 1 创建BufferedInputStream
        FileInputStream fis = new FileInputStream("d:\\abc.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);
        // 2 读取
        int data = 0;
        while((data = bis.read()) != -1){    // 缓冲区默认大小8*1024
            System.out.println((char)data);
        }
        // 用自己创建的缓冲流
        byte[] buf = new byte[1024];
        int count = 0;
        while((count = bis.read(buf)) != -1){
            System.out.println(new String(buf, 0, count));
        }

        // 3 关闭
        bis.close();
    }
  // 使用字节缓冲流写入文件
    public static void main(String[] args) throws Exception {
        // 1 创建BufferedInputStream
        FileOutputStream fos = new FileOutputStream("d:\\bbb.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        // 2 写入文件
        for (int i = 0; i < 4; i++) {  // 循环读取仍使用同一个缓冲区
            bos.write("hello\r\n".getBytes());// 写入同一个8k大小缓冲区 
            // \r\n换行
            bos.flush(); // 刷新到磁盘
        }
        // 3 关闭(内部调用flush方法)
        bos.close();
    }

对象流

ObjectOutputStream / ObjectInputStream

  • 增强了缓冲区功能

  • 增强了读写8种基本数据类型和字符串的功能

  • 增强了读写对象的功能

    • readObject() 从流中读取一个对象
    • writeObject(Object obj) 向流中写入一个对象
  • 使用流传输对象的过程称为序列化、反序列化

  • 序列化:从内存中把对象写入存储设备

  • 反序列化:从文件中读取对象 到内存

序列化

 // 使用ObjectOutputStream实现序列化
    public static void main(String[] args) throws IOException {
        // 1. 创建对象流
        FileOutputStream fos = new   FileOutputStream("d:\\st.bin");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        // 2. 序列化(写入操作)
        Student zhangsan = new Student("zs", 20);
        oos.writeObject(zhangsan);
        // 3. 关闭
        oos.close();//内含有flush()方法
        System.out.println("序列化完毕");
    }

反序列化

 // 使用ObjectInputSteam实现反序列化(读取重构对象)
    public static void main(String[] args) throws Exception {
        // 1. 创建对象流
        FileInputStream fis = new FileInputStream("d:\\st.bin");
        ObjectInputStream ois = new ObjectInputStream(fis);
        // 2. 读取文件(反序列化)
        Student s = (Student)ois.readObject(); //默认返回Object类型
        // 3. 关闭
        ois.close();
        System.out.println("执行完毕");
        System.out.println(s.toString());
    }

注意事项

  1. 某个类要想序列化必须实现Serializable接口
  2. 序列化类中的作为属性的对象的类也要求实现Serializable接口
  3. 序列化版本号ID(private static final long serialVersionUID),保证序列化的类和反序列化的类是同一个类
  4. 使用transient(短暂的)修饰属性,这个属性就不能被序列化,也就是不能被保存到硬盘,将对象写入再读取会发现属性成为了类型默认值
  5. 静态属性不能序列化,也就是不能被保存到硬盘
  6. 序列化多个对象,可以包装成集合类实现

编码方式

  • ISO-8859-1,使用一个字节最多表示256个字符
  • GBK使用1、2个字节表示
  • UTF-8 针对Unicode码表的可变长度字符编码,使用1、2、3个字节表示,单个汉字使用3字节
  • 编码和解码的方式不一致会出现乱码

字符流

字符流的父类(抽象类)

Reader 字符输入流

  • public int read(){} 读取一个字符
  • public int read(char[] c){}
  • public int read(char[] b, int off, int len){}

Writer 字符输出流

  • public void write(int n){} 写入一个字符

  • public void write(String str){} 写入一个字符串

  • public void write(char[] c){} 写入一个字符数组

FileReader使用

  public static void main(String[] args) throws Exception {
        // 1. 创建FileReader 文件字符输入流 (记事本创建时默认格式必须是UTF-8,尽量先写入再读取)
        FileReader fr = new FileReader("d:\\hell.txt");
// 2. 读取
// 2.1 单个字符读取
        int data = 0;
        while((data = fr.read()) != -1){
            System.out.print((char)data);// 读取一个字符,空格也算字符
        }
        char[] buf = new char[2];// 字符缓冲区读取
        int count = 0;
        while((count = fr.read(buf)) != -1){
            System.out.println(new String(buf, 0,count));
        }
 //3. 关闭
        fr.close();
    }

FileWriter使用

public static void main(String[] args) throws Exception{
        // 1. 创建FileWriter对象
        FileWriter fw = new FileWriter("d:\\hell.txt",true);
       // 2. 写入
        for(int i = 0; i < 1; i ++){
            fw.write("字符串");
            fw.write('a'); 
            char[] chars={'a','b','c'};
            fw.write(chars);
            fw.flush();  //有缓冲区
        }
       // 3. 关闭
        fw.close();
        System.out.println("执行完毕");
    }

文本文件复制

只能复制文本文件,不能复制图片(没有字符编码)或二进制文件,使用字节流可以复制任意文件

 public static void main(String[] args) throws Exception{
            // 1. 创建
            FileReader fr = new FileReader("d:\\hell.txt");
            FileWriter fw = new FileWriter("d:\\hell2.txt");
            // 2. 读写
            int data = 0;
            while((data = fr.read()) != -1){
                fw.write(data);
                fw.flush();
            }
            // 3. 关闭
            fw.close();
            fr.close();
        }

字符缓冲流

BufferedReader / BufferedWriter

高效读写;支持输入换行符;可一次写一行、读一行

        public static void main(String[] args) throws Exception{
            // 创建缓冲流
            FileReader fr = new FileReader("d:\\hello.txt");
            BufferedReader br = new BufferedReader(fr);
            // 读取
            // 1. 第一种方式
            char[] buf = new char[222];
            int count = 0;
            while((count = br.read(buf)) != -1){
                System.out.println(new String(buf, 0, count));
            }
            // 2. 第二种方式 一行一行读取
            String line = null;
            while((line = br.readLine()) != null){
                System.out.println(line);
            }
            // 关闭
            br.close// 此时会自动关闭fr
        }
 public static void main(String[] args) throws IOException {
        // 1. 创建BufferedWriter对象
        FileWriter fw = new FileWriter("d:\\hello.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        // 2. 写入
        for(int i = 0; i < 2; i ++){
            bw.write("写入的内容");
            bw.newLine(); // 写入一个换行符
            bw.flush();
        }
        // 3. 关闭
        bw.close(); // 此时会自动关闭fw
    }

PrintWriter

  • 封装了print() / println() 方法,支持写入后换行

  • 支持数据原样打印

public static void main(String[] args){
  // 1 创建打印流
  PrintWriter pw = new PrintWriter("d:\\print.txt");
  // 2 打印
  pw.println(true);
  pw.println(3.14);
  pw.println('a');
  pw.println(12);  // int类型
  // 3 关闭
  pw.close();
}

转换流

桥转换流 InputStreamReader / OutputStreamWriter

  • 字节流(硬盘)<===>字符流(内存)

  • 可设置字符的编码方式

  public static void main(String[] args) throws Exception{
        // 1 创建InputStreamReader对象
        FileInputStream fis = new FileInputStream("d:\\hello.txt");
        InputStreamReader isr = new InputStreamReader(fis, "utf-8");
                                                    // 文件编码与此处指定编码必须一致
        // 2 读取文件
        int data = 0;
        while((data = isr.read()) != -1){  // 读取单个字符
            System.out.print((char)data);
        }
        // 3 关闭
        isr.close();
    }
    public static void main(String[] args) throws Exception{
        // 1 创建OutputStreamReader对象
        FileOutputStream fos = new FileOutputStream("d:\\osw.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
        // 若文件不存在,此处指定编码就是文件编码;若文件存在,将文件编码改为此指定编码
        // 2 写入
        for(int i = 0; i < 3; i ++){
            osw.write("写入内容");  //  写入字符串
            osw.flush();
        }
        // 3 关闭
        osw.close();
    }

File类

概念:代表物理盘符中的一个文件或者文件夹

常用方法:

方法名 解释
createNewFile() 创建一个新文件
mkdir() 创建一个新目录
delete() 删除文件或空目录
exists() 判断文件或文件夹是否存在
getAbsolutePath() 获取文件的绝对路径
getName() 获取文件名,注意会带文件后缀
getParent() 获取文件/目录所在的目录
isDirectory() 判断是否是目录
isFile() 是否为文件
length() 获取文件的长度
listFiles() 列出目录中的所有内容
renameTo() 修改文件名为
deleteOnExit() jvm退出后删除文件(夹)
canWrite() 判断文件是否可写入

分隔符

public class FileTest {
    public static void main(String[] args){
        separator();
    }
    //  分隔符
    public static void separator(){
        System.out.println("路径分隔符" + File.pathSeparator);// 路径分隔符;
        System.out.println("名称分隔符" + File.separator);// 名称分隔符\
    }
}

文件操作

    //  文件操作
    public static void main(String[] args) throws IOException, InterruptedException {
        // 1 创建文件
        File file=new File("d:\\csb.txt");
        // 只是创建了文件对象,文件是否存在不一定
        if(!file.exists()){ // 是否存在
            boolean b = file.createNewFile();
            System.out.println("是否创建成功:"+b);
        }
        // 2 删除文件
        // 2.1 直接删除
        System.out.println("是否删除"+file.delete());
        // 2.2 使用jvm退出时删除
        file.deleteOnExit();
        Thread.sleep(5000); // 休眠5秒
        // 3 获取文件信息
        System.out.println("获取绝对路径" + file.getAbsolutePath());//返回绝对路径
        System.out.println("获取路径" + file.getPath());// 返回创建file对象时传入的路径
        System.out.println("获取文件名称" + file.getName());
        System.out.println("获取父目录" + file.getParent());
        System.out.println("获取文件长度" + file.length()); // 返回字节数
        System.out.println("文件创建时间" + new Date(file.lastModified())
                                                    .toLocaleString()) ;  
        // 4 判断
        System.out.println("是否可写" + file.canWrite());
        System.out.println("是否是文件" + file.isFile());
        System.out.println("是否隐藏" + file.isHidden());
    }

文件夹操作

public static void main(String[] args) throws Exception{
        // 1. 创建文件夹
        File dir = new File("d:\\test\\aaa\\ccc");
        // 只是创建文件夹对象,文件夹是否存在不一定
        System.out.println("文件夹名字:"+dir.toString());
        if(!dir.exists()){
            //boolean b = dir.mkdir(); // 只能创建单级目录
           boolean b=dir.mkdirs(); // 创建多级目录
            System.out.println("是否创建成功:"+b);
        }

        // 2. 删除文件夹
        // 2.1 直接删除
        dir.delete(); // 只能删除最底层空目录
        // 2.2 使用jvm删除
       dir.deleteOnExit();   // 只能删除最底层空目录

        // 3. 获取文件夹信息(文件夹长度返回值是不确定)
        System.out.println("获取绝对路径" + dir.getAbsolutePath());
        System.out.println("获取路径" + dir.getPath());
        System.out.println("获取文件夹名称" + dir.getName());
        System.out.println("获取父目录" + dir.getParent());
        System.out.println("文件夹创建时间" + new Date(dir.lastModified())                                                            .toLocaleString());

        // 4. 判断
        System.out.println("是否是文件夹" + dir.isDirectory());
        System.out.println("是否隐藏" + dir.isHidden());
        System.out.println("--------------");
        // 5. 遍历文件夹
        File dir2 = new File("C:\\");
        String[] files = dir2.list();
        for(String str : files){
            System.out.println(str);
        }
}

FileFilter接口(文件过滤器)

public interface FileFilter {
  boolean accept(File pathname);
}
public static void main(String[] args) {
        File dir=new File("C:\\Program Files (x86)\\Tencent\\Qzone");
        File[] files2 = dir.listFiles(new FileFilter(){
            @Override
            public boolean accept(File pathname){
                if(pathname.getName().endsWith(".dll")){
                    return true;
                }
                return false;
            }
        });

        for(File file : files2){
            System.out.println(file.getName());
        }
    }

递归遍历文件夹

 public static void main(String[] args) {
            listDir(new File("d:\\test"));
        }
        public static void listDir(File dir){
            File[] files = dir.listFiles();
            System.out.println(dir.getAbsolutePath());

            if(files != null && files.length > 0){
                for(File file : files){
                    if(file.isDirectory()){
                        listDir(file); // 递归
                    }else {
                        System.out.println(file.getAbsolutePath());
                    }
                }
            }

        }

递归删除文件夹

 public static void main(String[] args) {
        deleteDir(new File("d:\\test"));
        }
    public static void deleteDir(File dir){
        File[] files = dir.listFiles();
        if(files != null && files.length > 0){
            for(File file : files){
                if(file.isDirectory()){
                    deleteDir(file); // 递归
                }else{
                    // 删除文件
                    System.out.println(file.getAbsolutePath() + "删除" +                                                               file.delete());
                }}}
    System.out.println(dir.getAbsolutePath() + "删除" + dir.delete());
        //  删除文件夹
    } 

Properties

  • 持久的属性集合,线程安全的集合,继承HashTable,可保存在流中或从流中加载。

特点:

  1. 存储属性名和属性值(键值对)。
  2. 属性名和属性值都是字符串类型。
  3. 没有泛型。
  4. 和流有关。

示例代码:

public static void main(String[] args) throws IOException {

                Properties properties = new Properties();
                properties.setProperty("name", "csb");
                properties.setProperty("age", "23");
                //   keySet() || entrySet()
             Set<String> strings = properties.stringPropertyNames();
                //返回此属性列表中的键集
                for (String string : strings) {
                 System.out.println("Key:"+string+";"+
                 properties.getProperty(string));
                }

                // 输出
PrintWriter printWriter = new  
                         PrintWriter("d:\\Properties.txt");
                properties.list(printWriter);
                // 将属性列表输出到指定的输出流。
                printWriter.close();
    
                // 保存
                FileOutputStream fileOutputStream = 
        new   FileOutputStream ("d:\\PropertiesStore.properties");
                properties.store(fileOutputStream, "属性列表的描述");
                // 属性列表(键值对)写入输出流
                fileOutputStream.close();

                // 读取
                Properties properties1=new Properties();
                FileInputStream fis=
            new FileInputStream("d:\\PropertiesStore.properties");
                properties1.load(fis);
                //从输入流中读取属性列表(键值对)。
                fis.close();
                System.out.println(properties1.toString());
            }

Properties.txt内容:

-- listing properties --
age=23
name=csb

PropertiesStore.properties内容:

#\u5C5E\u6027\u5217\u8868\u7684\u63CF\u8FF0
#Tue Jul 06 13:58:58 CST 2021
age=23
name=csb
posted @ 2023-09-10 15:52  bobochen  阅读(12)  评论(0)    收藏  举报