Java基础之IO流(一)

时间:2022-07-22
本文章向大家介绍Java基础之IO流(一),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

IO概述

回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了。那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据读出来继续使用呢?其实要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等)上

  • 当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作
  • 当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作
  • 因此我们把这种输入和输出动作称为IO操作

IO的分类

Java IO一般包含两个部分:

  1. java.io包中堵塞型IO;
  2. java.nio包中的非堵塞型IO,通常称为NewIO。

学过操作系统的朋友都知道系统运行的瓶颈一般在于IO操作,一般打开某个IO通道需要大量的时间,同时端口中不一定就有足够的数据,这样read方法就一直等待读取此端口的内容,从而浪费大量的系统资源。有人也许会提出使用java的多线程技术啊!但是在当前进程中创建线程也是要花费一定的时间和系统资源的,因此不一定可取。Java New IO的非堵塞技术主要采用了Observer模式,就是有一个具体的观察者和=监测IO端口,如果有数据进入就会立即通知相应的应用程序。这样我们就避免建立多个线程,同时也避免了read等待的时间。不过本篇主要讲述java的堵塞型IO,就是我们通常应用的那个包。

Java的IO主要包含三个部分:

  1. 流式部分――IO的主体部分;
  2. 非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;
  3. 文件读取部分的与安全相关的类,如:SerializablePermission类。以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。

流式部分可以概括为:两个对应一个桥梁。

两个对应指:

  1. 字节流(Byte Stream)和字符流(Char Stream)的对应;
  2. 输入和输出的对应。一个桥梁指:从字节流到字符流的桥梁。对应于输入和输出为InputStreamReader和OutputStreamWriter。

在流的具体类中又可以具体分为:

  1. 介质流(Media Stream或者称为原始流Raw Stream)――主要指一些基本的流,他们主要是从具体的介质上,如:文件、内存缓冲区(Byte数组、Char数组、StringBuffer对象)等,读取数据;
  2. 过滤流(Filter Stream)――主要指所有FilterInputStream/FilterOutputStream和FilterReader/FilterWriter的子类,主要是对其包装的类进行某些特定的处理,如:缓存等。

File类

我们先从file类学起,file类是文件和目录路径名的抽象表示。

File类的构造函数

通过构造方法创建File对象

/**
 * 通过构造方法创建File对象
 */
public static void test1() {
    // File构造函数演示
    String pathName = "e:\test\Hello.java";
    // 注意:可以封装不存在文件或者文件夹,变成对象。
    File file1 = new File(pathName);
    System.out.println("file1 = " + file1);

    File file2 = new File("e:\test", "Hello.java");
    System.out.println("file2 = " + file2);

    // 将 parent 封装成 file 对象
    File dir = new File("e:\test");
    File file3 = new File(dir, "Hello.java");
    System.out.println("file3 = " + file3);

    //file1 = e:testHello.java
    //file2 = e:testHello.java
    //file3 = e:testHello.java
}

File类获取文件相关信息

创建完了File对象之后,那么File类中都有如下常用方法,可以获取文件相关信息

/**
 * File类获取文件相关信息
 */
public static void test2() {
    // 创建文件对象
    File file = new File("Test2.java");
    // 获取文件的绝对路径,即全路径
    String absPath = file.getAbsolutePath();
    // File中封装的路径是什么获取到的就是什么
    String path = file.getPath();
    // 获取文件名称
    String fileName = file.getName();
    // 获取文件大小
    long size = file.length();

    System.out.println("absPath = " + absPath);
    System.out.println("path = " + path);
    System.out.println("fileName = " + fileName);
    System.out.println("size = " + size);

    //absPath = F:JetBrainsmyProjectspringboot2-examplesTest2.java
    //path = Test2.java
    //fileName = Test2.java
    //size = 0
}

文件和文件夹的创建与删除等

/**
 * 文件和文件夹的创建与删除等
 */
public static void test3() throws IOException {
    // 对文件或者文件夹进行操作
    File file = new File("e:\test3.txt");
    // 创建文件,如果文件不存在,创建 true。 如果文件存在,则不创建 false。 如果路径错误,IOException。
    boolean b1 = file.createNewFile();
    System.out.println("b1 = " + b1);

    // 删除文件操作 - 慎用
    boolean b2 = file.delete();
    System.out.println("b2 = " + b2);

    // 判断文件是否存在
    boolean b3 = file.exists();
    System.out.println("b3 = " + b3);

    // 对目录操作 创建、删除、判断
    File dir = new File("e:\abc");
    // mkdir()创建单个目录;  mkdirs()创建多级目录
    boolean b4 = dir.mkdir();
    System.out.println("b4 = " + b4);

    // 删除目录时,如果目录中有文件,无法直接删除
    // 只有将目录中的内容都删除后,保证该目录为空。这个目录才可以删除。
    boolean b5 = dir.delete();
    System.out.println("b5 = " + b5);

    // 要判断是否是文件还是目录,必须先判断存在
    File file1 = new File("e:\hello.txt");
    // file1.mkdir();//file1.createNewFile(); // 要判断是否是文件还是目录,先判断存在。
    System.out.println("file1.isFile() = " + file1.isFile());
    System.out.println("file1.isDirectory() = " + file1.isDirectory());
    
    //b1 = true
    //b2 = true
    //b3 = false
    //b4 = true
    //b5 = true
    //file1.isFile() = false
    //file1.isDirectory() = false
}

获取目录下的所有文件和文件夹

文件都存放在目录(文件夹)中,那么如何获取一个目录中的所有文件或者目录中的文件夹呢?那么我们先想想,一个目录中可能有多个文件或者文件夹,那么如果File中有功能获取到一个目录中的所有文件和文件夹,那么功能得到的结果要么是数组,要么是集合。

/**
 * 获取目录下的所有文件和文件夹
 */
public static void test4() throws IOException {
    File dir = new File("e:\java_code");

    File file1 = new File(dir, "aaa");
    file1.mkdirs();

    File file2 = new File(dir, "a.txt");
    file2.createNewFile();

    //获取的是目录下的当前的文件以及文件夹的名称。
    String[] names = dir.list();
    for (String name :
            names) {
        System.out.println("name = " + name);
    }

    //获取目录下当前文件以及文件对象,只要拿到了文件对象,那么就可以获取其中想要的信息
    File[] files = dir.listFiles();
    for (File file :
            files) {
        System.out.println("file = " + file);
    }


    //name = a.txt
    //name = aaa
    //file = e:java_codea.txt
    //file = e:java_codeaaa
}

文件过滤器

通过listFiles()方法,我们可以获取到一个目录下的所有文件和文件夹,但能不能对其进行过滤呢?比如我们只想要一个目录下的指定扩展名的文件,或者包含某些关键字的文件夹呢

我们是可以先把一个目录下的所有文件和文件夹获取到,并遍历当前获取到所有内容,遍历过程中在进行筛选,但是这个动作有点麻烦,Java给我们提供相应的功能来解决这个问题

    /**
     * 文件过滤器
     * 获取扩展名为.java所有文件
     */
    public static void test5() {
        // 创建 File 对象
        File file = new File("e:\java_code");
        // 获取指定扩展名的文件,由于要对所有文件进行扩展名筛选,因此调用方法需要传递过滤器
        File[] files = file.listFiles(new MyFileFilter());
        // 遍历获取到的所有符合条件的文件
        for (File f :
                files) {
            System.out.println("f = " + f);
        }

        // f = e:java_codeb.java
    }



/**
 * 定义类实现文件名称FilenameFilter过滤器
 */
class MyFileFilter implements FilenameFilter {

    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(".java");
    }
}

值得一提的是 我们要注意这个用法 只能是下一级目录,不能说是2级 就比如例子中的 必须要是java_code/下的,就是说java_code/aaa/下的bbb.java 也是找不到的

递归打印所有子目录中的文件路径

/**
 * 递归打印所有子目录中的文件路径
 */
public static void test6() {
    File file = new File("e:\java_code");
    getFileAll(file);

    //file = e:java_codea.txt
    //file = e:java_codeaaab.java
    //file = e:java_codeb.java
}

public static void getFileAll(File file) {
    File[] files = file.listFiles();
    // 遍历当前目录下的所有文件和文件夹
    for (File f :
            files) {
        // 判断当前遍历到的是否为目录
        if (f.isDirectory()) {
            // 是目录,继续获取这个目录下的所有文件和文件夹
            getFileAll(f);
        } else {
            // 不是目录,说明当前f就是文件,那么就打印出来
            System.out.println("file = " + f);
        }
    }
}

File总结

File: 文件和目录路径名的抽象表示形式

构造方法

public File(String pathname) 通过给定的文件或文件夹的路径,来创建对应的File对象
public File(String parent, String child) 通过给定的父文件夹路径,与给定的文件名称或目录名称来创建对应的File对象
public File(File parent,  String child)通过给定的File对象的目录路径,与给定的文件夹名称或文件名称来创建对应的File对象

路径的分类

  1. 绝对路径, 带盘盘符 E:\work\a.txt
  2. 相对路径, 不带盘符 work\a.txt 注意: 当指定一个文件路径的时候,如果采用的是相对路径,默认的目录为 项目的根目录

常用方法

public boolean createNewFile()创建文件

返回值为true, 说明创建文件成功
返回值为false,说明文件已存在,创建文件失败


public boolean mkdir() 创建单层文件夹

创建文件夹成功,返回 true
创建文件夹失败,返回 false


public boolean mkdirs() 创建多层文件夹
public boolean delete()

删除此抽象路径名表示的文件或目录
如果此路径名表示一个目录,则该目录必须为空才能删除


public boolean isDirectory() 判断是否为文件夹
public boolean isFile() 判断是否为文件
public boolean exists() 判断File对象对应的文件或文件夹是否存在
public String getAbsolutePath() 获取当前File的绝对路径
public String getName() 获取当前File对象的文件或文件夹名称
public long length() 获取当前File对象的文件或文件夹的大小(字节)
public File[] listFiles() 获取File所代表目录中所有文件或文件夹的绝对路径