• [Java学习笔记] IO


    总结自廖雪峰大佬的教程

    Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)icon-default.png?t=LA46https://www.liaoxuefeng.com/wiki/1252599548343744

    目录

    File

    练习:打印所有文件和子文件夹的内容

    InputStream/OutputStream

    Filter模式(少量的类实现功能组合)



    File

    Java标准库的java.io.File对象表示一个文件或者目录:

    创建File对象本身不涉及IO操作

    • 可以获取路径/绝对路径/规范路径:getPath()/getAbsolutePath()/getCanonicalPath()
    • 可以获取目录的文件和子目录:list()/listFiles()
    • 可以创建或删除文件和目录。

    File对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个File对象,即使传入的文件或目录不存在,代码也不会出错,因为构造一个File对象,并不会导致任何磁盘操作。只有当我们调用File对象的某些方法的时候,才真正进行磁盘操作。

    例如,调用isFile(),判断该File对象是否是一个已存在的文件,调用isDirectory(),判断该File对象是否是一个已存在的目录:

    用File对象获取到一个文件时,还可以进一步判断文件的权限和大小:

    • boolean canRead():是否可读;
    • boolean canWrite():是否可写;
    • boolean canExecute():是否可执行;
    • long length():文件字节大小。

    对目录而言,是否可执行表示能否列出它包含的文件和子目录。

    有些时候,程序需要读写一些临时文件,File对象提供了createTempFile()来创建一个临时文件,以及deleteOnExit()在JVM退出时自动删除该文件。

    public class Main {
    
        public static void main(String[] args) throws IOException {
    
            File f = File.createTempFile("tmp-", ".txt"); // 提供临时文件的前缀和后缀
    
            f.deleteOnExit(); // JVM退出时自动删除
    
            System.out.println(f.isFile());
    
            System.out.println(f.getAbsolutePath());
    
        }
    
    }

    true

    /tmp/tmp-17585469961555042196.txt

    练习:打印所有文件和子文件夹的内容

    
    import java.io.File;
    import java.io.IOException;
    
    
    public class demo {
    
        public static void main(String[] args) throws IOException {
            File currentDir = new File(".");
            printAllFile(currentDir.getCanonicalFile());
        }
    
        static void printAllFile(File dir) {
            // 打印所有文件和子文件夹的内容
            File[] files = dir.listFiles();
            if(files != null){
                for(File f : files){
                    System.out.println(f.getName());
                }
            }
        }
    }
    

    InputStream/OutputStream

    Java标准库的java.io.InputStream/java.io.OutputStream定义了所有输入/输出流的超类:

    • FileInputStream实现了文件流输入,FileOutputStream实现了文件流输出;

    • ByteArrayInputStream在内存中模拟一个字节流输入, ByteArrayOutputStream在内存中模拟一个字节流输出。

    • 某些情况下需要手动调用OutputStreamflush()方法来强制输出缓冲区。

    • 总是使用try(resource)来保证正确关闭。

    InputStream并不是一个接口,而是一个抽象类,它是所有输入流的超类。这个抽象类定义的一个最重要的方法就是int read(),签名如下:

    public abstract int read() throws IOException;

    需要用try ... finally来保证InputStream在无论是否发生IO错误的时候都能够正确地关闭:

    public void readFile() throws IOException {
        InputStream input = null;
        try {
             // 定义1000个字节大小的缓冲区:
            byte[] buffer = new byte[1000];
            int n;
            while ((n = input.read(buffer)) != -1) { // 读取到缓冲区
                System.out.println("read " + n + " bytes.");
            }
        } finally {
            if (input != null) { input.close(); }
        }
    }
    

    try ... finally来编写上述代码会感觉比较复杂,更好的写法是利用Java 7引入的新的try(resource)的语法,只需要编写try语句,让编译器自动为我们关闭资源。推荐的写法如下:

    public void readFile() throws IOException {
        try (InputStream input = new FileInputStream("src/readme.txt")) {
             // 定义1000个字节大小的缓冲区:
            byte[] buffer = new byte[1000];
            int n;
            while ((n = input.read(buffer)) != -1) { // 读取到缓冲区
                System.out.println("read " + n + " bytes.");
            }
        } // 编译器在此自动为我们写入finally并调用close()
    }
    

    实际上,编译器并不会特别地为InputStream加上自动关闭。编译器只看try(resource = ...)中的对象是否实现了java.lang.AutoCloseable接口,如果实现了,就自动加上finally语句并调用close()方法。InputStreamOutputStream都实现了这个接口,因此,都可以用在try(resource)

    在调用InputStreamread()方法读取数据时,read()方法是阻塞的

    int n;
    n = input.read(); // 必须等待read()方法返回才能执行下一行代码
    int m = n;

    Filter模式(少量的类实现功能组合)

    当我们需要给一个“基础”InputStream附加各种功能时,我们先确定这个能提供数据源的InputStream,因为我们需要的数据总得来自某个地方,例如,FileInputStream,数据来源自文件:

    InputStream file = new FileInputStream("test.gz");
    

    紧接着,我们希望FileInputStream能提供缓冲的功能来提高读取的效率,因此我们用BufferedInputStream包装这个InputStream,得到的包装类型是BufferedInputStream,但它仍然被视为一个InputStream

    InputStream buffered = new BufferedInputStream(file);
    

    最后,假设该文件已经用gzip压缩了,我们希望直接读取解压缩的内容,就可以再包装一个GZIPInputStream

    InputStream gzip = new GZIPInputStream(buffered);
    

    无论我们包装多少次,得到的对象始终是InputStream,我们直接用InputStream来引用它,就可以正常读取:

    ┌─────────────────────────┐
    │GZIPInputStream          │
    │┌───────────────────────┐│
    ││BufferedFileInputStream││
    ││┌─────────────────────┐││
    │││   FileInputStream   │││
    ││└─────────────────────┘││
    │└───────────────────────┘│
    └─────────────────────────┘
    

    上述这种通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为Filter模式(或者装饰器模式:Decorator)。它可以让我们通过少量的类来实现各种功能的组合:

                     ┌─────────────┐
                     │ InputStream │
                     └─────────────┘
                           ▲ ▲
    ┌────────────────────┐ │ │ ┌─────────────────┐
    │  FileInputStream   │─┤ └─│FilterInputStream│
    └────────────────────┘ │   └─────────────────┘
    ┌────────────────────┐ │     ▲ ┌───────────────────┐
    │ByteArrayInputStream│─┤     ├─│BufferedInputStream│
    └────────────────────┘ │     │ └───────────────────┘
    ┌────────────────────┐ │     │ ┌───────────────────┐
    │ ServletInputStream │─┘     ├─│  DataInputStream  │
    └────────────────────┘       │ └───────────────────┘
                                 │ ┌───────────────────┐
                                 └─│CheckedInputStream │
                                   └───────────────────┘
  • 相关阅读:
    找出数组中出现次数超过一半的数字(众数)
    消失的两个数字(1-N缺两个数)
    47. Permutations II
    137. Single Number II
    Go语言内存分配(详述 转)
    Go语言内存分配(简述 转)
    redis分布式锁
    Golang调度器GMP原理与调度全分析(转 侵 删)
    android framework navigationbar自定义
    android studio使用中遇到的问题
  • 原文地址:https://www.cnblogs.com/Knight02/p/15799041.html
Copyright © 2020-2023  润新知