首页 > 技术文章 > Java-IO流框架

lx2001 2021-07-13 19:11 原文

1、流的概念

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

2、流的分类

2.1、按方向(重点)

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

2.2、按单位

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

2.3、按功能

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

3、字节流

字节流的父类(抽象类)

//InputStream 字节输入流
public int read(){}
public int read(byte[] b){}
public int read(byte[] b, int off, int len){}

// OutputStream 字节输出流
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b, int off, int len){}

3.1、文件字节流

package com.liuxiang.IO;

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

/**
 * 演示FileInputStream的使用
 * 文件字节输入流
 * @author 86187
 */

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建FileInputStream,并指定文件路径
        FileInputStream fileInputStream = new FileInputStream("d:\\aaa.txt");

        // 2.读取文件 read()
        // 2.1单字节读取
//        int data = 0;
//        while((data=fileInputStream.read())!=-1){
//            System.out.print((char)data);
//        }
        // 2.2一次读取多个字节
        byte[] bytes = new byte[3];
        int count = 0;
        while ((count=fileInputStream.read(bytes))!=-1){
            System.out.println(new String(bytes,0,count));
        }

        // 3.关闭
        fileInputStream.close();
        System.out.println("执行完毕");
    }
}

package com.liuxiang.IO;

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

/**
 * 演示FileOutputStream的使用
 * 文件字节输出流
 * @author 86187
 */

public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建文件字节输出流对象
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\bbb.txt",true); // true表示不覆盖原来的写入

        // 2.写入文件
        fileOutputStream.write(97); // 97是字符a对应的ASCII编码
        fileOutputStream.write('b');
        fileOutputStream.write('c');
        String s = "   liuxiang";
        fileOutputStream.write(s.getBytes());

        // 3.关闭
        fileOutputStream.close();
        System.out.println("执行完毕");
    }
}

图片复制实例

package com.liuxiang.IO;

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

public class CopyPictureDemo {
    public static void main(String[] args) throws IOException {
        // 1 创建流
        // 1.1 文件字节输入流
        FileInputStream fis = new FileInputStream("d:\\1.jpg");
        // 1.2 文件字节输出流
        FileOutputStream fos = new FileOutputStream("d:\\2.jpg");
        // 2 边读边写
        byte[] buf = new byte[1024];
        int count = 0;
        while((count = fis.read(buf)) != -1){
            fos.write(buf, 0, count);
        }
        System.out.println("复制图片成功");
        
        // 3 关闭
        fis.close();
        fos.close();
    }
}

3.2、字节缓冲流

缓冲流:BufferedInputStream/ BufferedOutputStream

  • 提高IO效率,减少访问磁盘次数
  • 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close
package com.liuxiang.IO;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 使用字节缓冲流读取
 * BufferedInputStream
 * @author 86187
 */

public class BufferedInputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建BufferedInputStream对象
        FileInputStream fis = new FileInputStream("d:\\aaa.txt");
        BufferedInputStream bis = new BufferedInputStream(fis);

        // 2.读取
        int data = 0;
        while ((data=bis.read())!=-1){
            System.out.print((char)data);
        }

        // 自己创建缓冲区
        byte[] buf = new byte[1024];
        int count = 0;
        while ((count=bis.read(buf))!=-1){
            System.out.print(new String(buf,0,count));
        }
        System.out.println("读取完毕");

        // 3.关闭
        bis.close();
    }
}
package com.liuxiang.IO;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 使用字节缓冲流写入
 * BufferedOutputStream
 * @author 86187
 */

public class BufferedOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建字节输出缓冲流
        FileOutputStream fos = new FileOutputStream("d:\\buffer.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        // 2.写入文件
        for (int i=0;i<10;i++){
            bos.write("helloworld".getBytes()); //写入缓冲区,还没有写入D盘文件
            bos.flush(); // 刷新到D盘文件中
        }

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

4、对象流

//对象流:ObjectOutputStream / ObjectInputStream
  • 增强了缓冲区功能
  • 增强了读写8种基本数据类型和字符串的功能
  • 增强了读写对象的功能
    • readObject() 从流中读取一个对象
    • writeObject(Object obj) 向流中写入一个对象

使用流传输对象的过程称为序列化、反序列化

4.1、序列化

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

4.2、反序列化

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

4.3、注意事项

  • 某个类要想序列化必须实现Serializable接口

  • 序列化类中对象属性要求实现Serializable接口

  • 序列化版本号ID,保证序列化的类和反序列化的类是同一个类

  • 使用transient修饰属性,这个属性就不能序列化

  • 静态属性不能序列化

  • 序列化多个对象,可以借助集合来实现

5、字符编码

  • ISO-8859-1:收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号
  • UTF-8:针对Unicode码表的可变长度字符编码
  • GB2312:简体中文
  • GBK:简体中文、扩充
  • BIG5台湾:繁体中文

当编码方式与解码方式不一致时,会出现乱码。

6、字符流

字符流的父类(抽象类)

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){}

6.1、文件字符流

package com.liuxiang.IO;

/**
 * 使用FileReader读取文件
 * @author 86187
 */

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

public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建FileReader 文件字符输入流
        FileReader fr = new FileReader("d:\\aaa.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.print(new String(buf, 0, count));
        }
        // 3. 关闭
        fr.close();
    }
}
package com.liuxiang.IO;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 使用FileWriter写入文件
 * @author 86187
 */

public class FileWriterDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建FileWriter对象
        FileWriter fw = new FileWriter("d:\\ccc.txt");
        // 2. 写入
        for(int i = 0; i < 10; i ++){
            fw.write("写入的内容");
            fw.flush();
        }
        // 3. 关闭
        fw.close();
        System.out.println("执行完毕");
    }
}

文本复制实例

package com.liuxiang.IO;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 使用FileReader和FileWriter复制文本文件
 * 使用字符流不能复制图片或二进制文件,使用字节流可以复制任意文件
 */

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

}

6.2、字符缓冲流

// 字符流:BufferedReader / BufferedWriter

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

package com.liuxiang.IO;

/**
 * 使用字符缓冲流读取文件
 * BufferedReader
 * @author 86187
 */

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        // 创建缓冲流
        FileReader fr = new FileReader("d:\\write.txt");
        BufferedReader br = new BufferedReader(fr);
        // 读取
        // 1. 第一种方式
        char[] buf = new char[1024];
        int count = 0;
        while((count = br.read(buf)) != -1){
            System.out.print(new String(buf, 0, count));
        }
        // 2. 第二种方式 一行一行读取
        String line = null;
        while((line = br.readLine()) != null){
            System.out.print(line);
        }

        // 关闭
        br.close();
    }
}
package com.liuxiang.IO;

/**
 * 使用字符缓冲流写入文件
 * BufferedWriter
 * @author 86187
 */

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建BufferedWriter对象
        FileWriter fw = new FileWriter("d:buffer.txt");
        BufferedWriter bw = new BufferedWriter(fw);
        // 2. 写入
        for(int i = 0; i < 10; i ++){
            bw.write("写入的内容");
            bw.newLine(); // 写入一个换行符
            bw.flush();
        }
        // 3. 关闭
        bw.close(); // 此时会自动关闭fw
    }
}

7、打印流PrintWriter

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

支持数据原样打印

package com.liuxiang.IO;

/**
 * 演示PrintWriter的使用
 * @author 86187
 */

import java.io.FileNotFoundException;
import java.io.PrintWriter;

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

8、转换流

桥转换流 InputStreamReader / OutputStreamWriter

可将字节流转换为字符流

可设置字符的编码方式

public static void main(String[] args) throws IOException {
  // 1 创建InputStreamReader对象
  FileInputStream fis = new FisInputStream("d:\\aaa.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 IOException {
  // 1 创建OutputStreamReader对象
  FileOutputStream fos = new FisOutputStream("d:\\bbb.txt");
  OutputStreamWRITER osw = new OutputStreamReader(fos, "utf-8");
  // 2 写入
  for(int i = 0; i < 10; i ++){
    osw.write("写入内容");
    osw.flush();
  }
  // 3 关闭
  osw.close();
}

9、File类

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

方法:

  • createNewFile() //创建一个新文件
  • mkdir() //创建一个新目录
  • delete() //删除文件或空目录
  • exists() //判断File对象所对象所代表的对象是否存在
  • getAbsolutePath() //获取文件的绝对路径
  • getName() //取得名字
  • getParent() //获取文件/目录所在的目录
  • isDirectory () //是否是目录
  • isFile() //是否是文件
  • length() //获得文件的长度
  • listFiles() //列出目录中的所有内容
  • renameTo() //修改文件名为
package com.liuxiang.IO;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Date;

/**
 * File类的使用
 * (1)分隔符
 * (2)文件操作
 * (3)文件夹操作
 * @author 86187
 */

public class FileDemo {
    public static void main(String[] args) throws Exception {
        separator();
        fileOpen();
        directoryOpe();
    }
    public static void separator() {
        System.out.println("路径分隔符"+ File.pathSeparator);
        System.out.println("名称分隔符"+File.separator);
    }

    // 文件操作
    public static void fileOpen() throws IOException {
        // 1. 创建文件 createNewFile()
        File file = new File("d:\\abc.txt");
        if(!file.exists()){
            boolean b = file.createNewFile();
            System.out.println("创建结果"+b);
        }

        // 2. 删除文件
        // 2.1 直接删除
//        file.delete(); // 成功true
//        // 2.2 使用jvm退出时删除
//        file.deleteOnExit();

        // 3. 获取文件信息
        System.out.println("获取绝对路径" + file.getAbsolutePath());
        System.out.println("获取路径" + file.getPath());
        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 directoryOpe() throws Exception{
        // 1. 创建文件夹
        File dir = new File("d:\\aaa\\bbb");
        System.out.println(dir.toString());
        if(!dir.exists()){
            //dir.mkdir(); // 只能创建单级目录
            dir.mkdirs(); // 创建多级目录
        }

        // 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("获取文件长度" + dir.length());
        System.out.println("文件夹创建时间" + new Date(dir.lastModified()).toLocaleString());

        // 4. 判断
        System.out.println("是否是文件夹" + dir.isFile());
        System.out.println("是否隐藏" + dir.isHidden());

        // 5. 遍历文件夹
        File dir2 = new File("d:\\aaa\\bbb");
        String[] files = dir2.list();
        for(String string : files){
            System.out.println(string);
        }

        // FileFilter接口的使用
        // 当调用File类中的listFiles()方法时,支持传入FileFilter接口接口实现类,
        // 对获取文件进行过滤,只有满足条件的文件的才可出现在listFiles()的返回值中。
        File[] files2 = dir2.listFiles(new FileFilter(){
            @Override
            public boolean accept(File pathname){
                if(pathname.getName().endsWith(".jpg")){
                    return true;
                }
                return false;
            }
        });
        for(File file : files2){
            System.out.println(file.getName());
        }
    }
}

9.1、递归遍历文件夹

 public static void main(String[] args) throws Exception {
  listDir(new File("d:\\myfiles"));
}
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());
      }
    }
  }
}

9.2、递归删除文件夹

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

10、Properties属性集合

特点

  • 存储属性名和属性值
  • 属性名和属性值都是字符串类型
  • 没有泛型
  • 和流有关
package com.liuxiang.IO;

import java.io.*;
import java.util.Properties;
import java.util.Set;

/**
 * 演示Properties集合的使用
 * @author 86187
 */

public class PropertiesDemo {
    public static void main(String[] args) throws IOException {
        // 1.创建集合
        Properties properties = new Properties();
        // 2.添加数据
        properties.setProperty("username","zhangsan");
        properties.setProperty("age","20");
        System.out.println(properties.toString());
        // 3.遍历
        Set<String> set = properties.stringPropertyNames();
        for (String pro:set) {
            System.out.println(pro+"====="+properties.getProperty(pro));
        }
        // 4.和流有关的方法 列表list()
        PrintWriter pw = new PrintWriter("d:\\print.txt");
        properties.list(pw);
        pw.close();
        // 5.和流有关的方法 保存store()
        FileOutputStream fos = new FileOutputStream("d:\\store.properties");
        properties.store(fos,"注释");
        fos.close();

        // 6.和流有关的方法 加载load()
        Properties properties1 = new Properties();
        FileInputStream fis = new FileInputStream("d:\\store.properties");
        properties1.load(fis);
        fis.close();
        System.out.println(properties1.toString());
    }
}

推荐阅读