一、介绍

  • IO 的发展历程

java.io 包早在 JDK 1.0 就已推出,其中经历过几个版本分别为 BIO ( block io,jdk1.0 ) 阻塞IO、NIO ( non-block io,jdk1.5 ) 非阻塞IO、AIO ( asynchronou io,jdk1.7 ) 异步 IO 或 叫 NIO2。

  • IO 的结构体系

从大类来说 IO 分为 字符流 和 字节流 ,从方向来说分别为 输入流输出流,下面又分了有种类,最常用的有:文件流、缓冲流等。

在整个 java.io 包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable,掌握了这些IO的核心操作那么对于Java中的IO体系也就有了一个初步的认识了

  • 什么时候用字符流?什么时候用字节流 

字节流是一个万能流,什么文件都能读取,字符流只能读纯文本的文件,但是为了提高性能,纯文本文件选择字符流,非纯文本文件选择字节流。

二、IO 常用类的使用例子

可以先去看看常用类的使用方法

  • 文件类(File)

用于获得操作系统文件和对文件相应的操作

运用递归获取指定目录所有文件

public static void main(String[] args) throws IOException {
        String pathfile = "D:"+File.separator+"demo";
        File file = new File(pathfile);
        file(file);
    }

    public static void file(File file) throws IOException {
        //1.判断文件
        if(!file.exists()){
            throw new FileNotFoundException("文件不存在");
        }
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.isDirectory()){
                file(f);
            }else {
                System.out.println(f);
            }
        }

    }

上面这段代码会输出所有文件路径,看着好像有点累,想整个父子对应关系的数据,优化一下

先定义一下父子对应关系的类:点击查看类

private static List<Tree> list = new ArrayList<>();//用来存放数据
private static long id = 0;//因为测试使用,当初主键id来用

public static void file(String filepath,long parentid) throws FileNotFoundException {
        File file = new File(filepath);
        //1.判断文件
        if(!file.exists()){
            throw new FileNotFoundException("文件不存在");
        }
        //2.是文件该怎么执行
        if(file.isFile()){
            String name = file.getName();
            String path = file.getAbsolutePath();
            Tree tree = new Tree(id++,name,path,parentid);
            list.add(tree);
            return ;
        }
        //3.获取文件夹路径下面的所有文件递归调用;
        if(file.isDirectory()){
            String name = file.getName();
            String path = file.getAbsolutePath();
            Tree tree = new Tree(id++,name,path,parentid);
            list.add(tree);
            String[] list = file.list();
            for (int i = 0;i<list.length;i++){
                String s = list[i];
                String newFilePath = path+File.separator+s;//根据当前文件夹,拼接其下文文件形成新的路径
                file(newFilePath,tree.getId());
            }
        }
    }

    public static void main(String[] args) {

        String filepath="D:"+File.separator+"demo";//默认路径,扫描此文件夹下面的所有文件
        int parentid = 0;  //初始化父节点id
        try {
            file(filepath,parentid);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < list.size(); i++) {
            Tree tree = list.get(i);
            System.out.println("id:"+tree.getId()+"  parentId:"+tree.getPid()+"=="+tree.getName());
        }
    }

这个函数有三个很重要部分:两个静态参数(list、id)、文件路径、父id(和id是对应的,id是没有重复的,每次都是 i++ 操作)

id:0  parentId:0==demo
id:1  parentId:0==demo1.txt
id:2  parentId:0==test
id:3  parentId:2==demo.txt
id:4  parentId:2==import.txt

Process finished with exit code 0

但我们还想要一个树形结构的数据,我们转换一下,可以看我写的这篇:转换树形

--demo
--demo1.txt
--test
  --demo.txt
  --import.txt

Process finished with exit code 0

读取文件之后,我们还想要输入输出里面的东西,io 包下有输出输入流

  • 输入输出流(InputStream、OutputStream)

InputStream、OutputStream 都是抽像类而我们要用的是它的实现类文件输入输出流(FileInputStream、FileOutputStream)

FileInputStream 类有三个构造用来读取文件,常用的有两个

//可接受一个 String 类型的路径
public FileInputStream(String name) throws FileNotFoundException
// 可接受一个 文件类
public FileInputStream(File file) throws FileNotFoundException

FileOutputStream 类有五个构造用来读取文件,常用的有四个

//可接收一个String类型的路径
public FileOutputStream(String name) throws FileNotFoundException
//可接收一个String类型的路径和一个是否可追加的布尔类型,true代表追加,false代表覆盖
public FileOutputStream(String name, boolean append) throws FileNotFoundException
//可接收一个文件对象
public FileOutputStream(File file) throws FileNotFoundException
//可接收一个文件对象和一个是否可追加的布尔类型,true代表追加,false代表覆盖
public FileOutputStream(File file, boolean append) throws FileNotFoundException

下面讲一个读取和写入的例子

public static void demo1(){
        String pathfile = "D:"+File.separator+"demo"+File.separator+"test"+File.separator+"demo.txt";
        File file = new File(pathfile);
        try {
            if (file.exists()){
                InputStream fis = new FileInputStream(file);
                byte[] bytes = new byte[1024];
                int len = 0;
                while ((len = fis.read(bytes)) > 0){
                    System.out.println(new String(bytes));
                }
            }else {
                file.createNewFile();
                OutputStream fos = new FileOutputStream(file);
                fos.write(new String("这是一个纯文本文件").getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

逻辑很简单就是先构造一个文件,文件存在输出文件里面的内容,不存在则创建文件,再写入内容。

再看一个例子:复制字节码

public static void copyBytes(String from,String to) throws IOException {
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(from);
            outputStream = new FileOutputStream(to);
            byte[] b = new byte[1024];
            int i = -1;

            while ((i = inputStream.read(b)) != -1){
                outputStream.write(b);
            }
        }finally {
            if (inputStream != null){
                inputStream.close();
            }
            if (outputStream != null){
                outputStream.close();
            }
        }
    }
  • Writer、Reader

用法和字节流差不多

public static void copyCharacters(String from,String to) throws IOException{
        Reader reader = null;
        Writer writer = null;
        try {
            reader = new FileReader(from);
            writer = new FileWriter(to);
            char[] c = new char[50];
            int i = -1;
            while ((i = reader.read(c)) != -1){
                System.out.println(c);
                writer.write(c);
            }

        }finally {
            if (reader != null){
                reader.close();
            }
            if (writer != null){
                writer.close();
            }
        }
    }
  • 序列化(Serializable)

序列化是一个空接口,或者说它是一个标识,实现了 Serializable 接口的类就可以序列化,序列化指读写硬盘操作。