【Java】IO 流

2021/12/29 1:07:21

本文主要是介绍【Java】IO 流,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

【Java】IO 流

1 File 类

File 类是文件或目录的抽象表示,通过它可以实现对文件或目录信息的操作和管理。File 类能新建、删除、重命名文件和目录,但 File 类不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。想要在 Java 程序中表示一个真实存在的文件或目录,那么必须有一个 File 对象,但是 Java 程序中的一个 File 对象,可能没有一个真实存在的文件或目录。File 对象可以作为参数传递给流的构造器。

1.1 File 类的常用构造器

File(String pathname)

以 pathname 为路径创建 File 对象,可以是绝对路径或者相对路径,如果 pathname 是相对路径,则默认的当前路径在系统属性 user.dir 中存储。

  • 绝对路径:是一个固定的路径,从盘符开始。
  • 相对路径:是相对于某个位置开始。

File(String parent, String child)

以 parent 为父路径,child 为子路径创建 File 对象。

File(File parent, String child)

根据一个父 File 对象和子文件路径创建 File 对象

 @Test
    public void test1() {

        // 构造器1
        File file1 = new File("hello.txt");    // 相当于当前 module
        File file2 = new File("D:\\document\\he.txt");    // "\\" 第一个为转义字符

        // 构造器2
        File file3 = new File("D:\\document\\md文档", "Java 学习笔记");

        // 构造器3
        File file4 = new File(file3, "hi.txt");
        
    }

1.2 路径分隔符

路径中的每级目录之间用一个路径分隔符隔开。

路径分隔符和系统有关:

  • windows 和 DOS 系统默认使用 “” 来表示。
  • UNIX 和 URL 使用 “/” 来表示。

注意:Java 程序支持跨平台运行,因此路径分隔符要慎用。为了解决这个隐患,File 类提供了一个常量:public static final String separator。它可以根据操作系统,动态的提供分隔符。

// 下列两种情况效果相同
File file1 = new File("d:\\document\\hello.txt");
File file2 = new File("d:" + File.separator + "document" + File.separator + "hello.txt");

1.3 File 类的常用方法

通过 File 类中的方法可以实现对文件和目录的操作和管理。下面是 File 类中常用的方法。

File 类的获取功能:

  • public String getName():返回文件或目录的名称。

  • public String getPath():获取路径。

  • public String getParent():获取上层文件目录路径。若无,返回 null。

  • public String getAbsolutePath():获取绝对路径。

  • public long length():获取文件长度(即:字节数)。不能获取目录的长度。

  • public long lastModified():获取最后一次的修改时间,毫秒值。

    如下两个方法适用于文件目录:

  • public String[] list():获取指定目录下的所有文件或者文件目录的名称数组。

  • public File[] listFiles() :获取指定目录下的所有文件或者文件目录的 File 数组。

File 类的重命名功能:

  • public boolean renameTo(File dest):把文件重命名为指定的文件路径,成功则返回 true,否则返回 false。

比如以 file1.renameTo(file2) 为例,想要保证返回 true,需要 file1 在硬盘中是存在的,且 file2 不能在硬盘中存在。

File 类的判断功能:

  • public boolean isDirectory():判断是否是文件目录。
  • public boolean isFile():判断是否是文件。
  • public boolean exists():判断是否存在。
  • public boolean canRead():判断是否可读。
  • public boolean canWrite():判断是否可写。
  • public boolean isHidden():判断是否隐藏。

File 类的创建功能:

  • public boolean createNewFile():创建文件。若文件存在,则不创建,返回 false。
  • public boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
  • public boolean mkdirs():创建文件目录。如果上层文件目录不存在,一并创建。

注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下。

File 类的删除功能:

  • public boolean delete():删除文件或者文件夹。

注意事项:

Java 中的删除不走回收站。

要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。

2 IO 流及流的分类

2.1 IO 流概述

I/O 是 Input/Output 的缩写, I/O 技术是非常实用的技术,用于处理设备之间的数据传输。如:读/写文件,网络通讯等。在 Java 程序中,对于数据的输入/输出操作以 “流 (stream)” 的方式进行。

流 (stream) 是一组有序的数据序列。根据操作的类型,分为输入流和输出流两种。输入流的指向称为源,程序从指向源的输入流中读取源中的数据。当程序需要读取数据时,就会开启一个通向数据源的流,这个数据源可以是文件、内存或是网络连接。而输出流的指向是字节要去的目的地,程序通过向输出流中写入数据把信息传递到目的地。当程序需要写入数据时,就会开启一个通向目的地的流。

Java 本身不包含 I/O 语句,而是通过 Java API 提供的 Java.io 包完成 I/O。java.io 包下提供了各种 “流” 类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

  • 输入 input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  • 输出 output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

注意:输入输出是相对的,需要清楚是站在谁的角度说明问题。比如:甲借给乙 100 块,对甲来说,甲是输出端;对乙来说,乙是输入端。

2.2 流的分类

按照 流的方向 划分可以分为输入流 (InputStream) 和输出流 (OutputStream) 。

  • 输入流:Java 程序可以打开一个从某种数据源(文件、内存等)到程序的一个流,从这个流中读取数据,这就是输入流。因为流是有方向的,所以只能从输入流中读取数据,而不能向它写数据。
  • 输出流:Java 程序可以打开到某种目标的流,把数据顺序写到该流中,从而把程序中的数据保存在目标中。只能将数据写到输出流中,而不能从输出流中读取数据。

按照 流所关联的是否为最终数据源或目标 来划分,流可以分为节点流 (node stream) 和处理流 (processing stream)。

  • 节点流:直接与最终数据源或目标关联的流为节点流。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EGtLc6L0-1640706447490)(D:\单宇楠\md文档\md插图\IO流2.png)]

  • 处理流:不直接连到数据源或目标,而是对其他 I/O 流进行连接和封装的流为处理流。节点流一般只提供一些基本的读写操作方法,而处理流会提供一些功能比较强大的方法。所以,在实际应用中通常将节点流与处理流结合起来使用以满足不同的 I/O 需求。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ZUO6c4l-1640706447492)(D:\单宇楠\md文档\md插图\IO流3.png)]

按照 流所操作的数据单元 来划分,流可以分为字节流和字符流。

  • 字节流:以字节为基本单元进行数据的 I/O,可用于二进制数据的读写。
  • 字符流:以字符为基本单元进行数据的 I/O,可用于文本数据的读写。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6CsB6Pci-1640706447493)(D:\单宇楠\md文档\md插图\IO流1.png)]

2.3 流的体系结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hq0nxSY8-1640706447494)(D:\单宇楠\md文档\md插图\io流4.jpg)]

2.4 输入输出流

输入输出流一般分为字节输入流、字节输出流、字符输入流和字符输出流 4 种。

2.4.1 字节流 InputStream & OutputStream

InputStream(典型实现类:FileInputStream):

抽象类 java.io.InputStream 是所有字节输入流的父类,该类定义了读取字节数据的基本方法。下面是 InputStream 类中常用的方法。

  • public abstract int read():读一个字节作为方法的返回值。返回 0 到 255 范围内的 int 字节值。如果返回 -1,则表示到达流的末尾。
  • public int read(byte[] b):将读取的数据保存在一个字节数组中,并返回读取的字节数。
  • public int read(byte[] b, int off, int len):从输入流中读取 len 个字节存储在初始偏移量为 off 的字节数组中,返回实际读取的字节数。如果因为流位文件末尾而没有可用的字节,则返回 -1。
  • public long skip(long n):从输入流中最多跳过 n 个字节,返回跳过的字节数。
  • public int available():返回此输入流中可以不受阻塞地读取(跳过)的字节数。
  • public void close() throws IOException:关闭输入流,释放与流相关联的所有系统资源。
  • public void mark(int readlimit):标记当前的位置,参数 readlimit 用于设置从标记位置处开始可以读取的最大字节数。
  • public void reset():将输入流重新定位到最后一次 mark 方法标记的位置。
  • public boolean markSupported():如果输入流支持 mark 和 reset 方法,则返回 true;否则返回false。

OutputStream(典型实现类:FileOutputStream):

抽象类 java.io.OutputStream 是所有字节输出流的父类,该类定义了输出字节数据的基本方法。下面是 OutputStream 类中常用的方法。

  • public abstract void write(int b):将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入 0~255 范围的。
  • public void write(byte[]b):将 b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定:与调用 write(b, 0, b.length) 的效果完全相同。
  • public void write(byte[] b, int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
  • public void flush() throws IOException:刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。
  • public void close() throws IOException:关闭输出流,并释放与流关联的所有系统资源。

注意:

  1. 异常的处理:问了保证流资源一定可以执行关闭操作。需要使用 try-catch-finally 处理。
  2. 读入的文件一定要存在,否则就会报 FileNotFoundException。
  3. 程序中打开的文件 IO 资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件 IO 资源。
  4. FileInputStream 从文件系统中的某个文件中获得输入字节。FileInputStream 用于读取非文本数据之类的原始字节流。要读取字符流,需要使用 FileReader。
  5. FileOutputStream 从文件系统中的某个文件中获得输出字节。FileOutputStream 用于写出非文本数据之类的原始字节流。要写出字符流,需要使用 FileWriter

2.4.2 字符流 Reader & Writer

Reader(典型实现类:FileReader):

抽象类 java.io.Reader 是所有字符输入流的父类,该类定义了读取字符数据的基本方法。下面是 Reader 类中常用的方法。

  • public int read():读一个字符作为方法的返回值,如果返回 -1,则表示到达流的末尾。
  • .public int read(char[] cbuf):读字符保存在数组中,并返回读取的字符数。如果已到达流的末尾,则返回 -1。
  • public abstract int read(char[] cbuf, int off, int len):读字符存储在数组的指定位置,存到数组 cbuf中,从off处开始存储,最多读 len 个字。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。
  • public long skip(long n):从输人流中最多跳过n个字符,返回跳过的字符数。
  • public boolean ready():当输入流准备好可以读取数据时返回 true,否则返回 false。
  • public boolean markSupported():当输入流支持 mark 方法时返回 true,否则返回 false。
  • public void mark(int readAheadLimit): 标记当前的位置,参数用于设置从标记位置处开始可以读取的最大字符数。
  • public void reset():将输入流重新定位到最后一次 mark 方法标记的位置。
  • public abstract void close() throws IOException:关闭输人流并释放与流关联的所有系统资源。

Writer(典型实现类:FileWriter):

抽象类 java.io.Writer 是所有字符输出流的父类,该类定义了输出字符数据的基本方法。下面是 Writer 类中常用的方法。

  • public void write(int c):写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。 即写入0 到 65535 之间的 Unicode 码。
  • public void write(char[]cbuf):写入字符数组。
  • public abstract void write(char[]cbuf, int off, int len):写入字符数组的某一部分。从 off 开始,写入 len 个字符。
  • public void write(String str)::将字符串 str 中的全部字符写入输出流。
  • public void write(String str, int off, int len):将字符串 str 中,从偏移量 off 开始的 len 个字符写人输出流。
  • public abstract void flush():刷新输出流,强制写出所有缓冲的输出字符。
  • public void close() throws IOException:关闭此输出流并释放与该流关联的所有系统资源。

注意:

因为字符流直接以字符作为操作单位,所以 Writer 可以用字符串来替换字符数组,即以 String 对象作为参数。

  • void write(String str);
  • void write(String str, int off, int len);

2.4.3 输入输出的标准化过程

输入过程:

  1. 创建 File 类的对象,指明读取的数据的来源。(要求文件一定要存在)。
  2. 创建相应的输入流,将 File 类的对象作为参数,传入流的构造器中。
  3. 具体的读入过程:创建相应的 byte[] 或 char[]。
  4. 关闭流资源。(程序中出现异常需要使用 try-catch-finally 处理)

输出过程:

  1. 创建 File 类的对象,指明写出的数据的来源。(不要求文件一定存在)。
  2. 创建相应的输出流,将 File 类的对象作为参数,传入流的构造器中。
  3. 具体的写出过程:write(char[] / byte[] buffer, 0, len)。
  4. 关闭流资源。(程序中出现异常需要使用 try-catch-finally 处理)

2.5 节点流(或文件流)

2.5.1 读取文件

  1. 建立一个流对象,将已存在的一个文件加载进流。

    FileReader fr = new FileReader(new File(“Test.txt”));
    
  2. 创建一个临时存放数据的数组。

    char[] ch = new char[1024];
    
  3. 调用流对象的读取方法将流中的数据读入到数组中。

    fr.read(ch);
    
  4. 关闭资源。

    fr.close();
    

    示例:

    FileReader fr = null;
    try {
    	fr = new FileReader(new File("c:\\test.txt"));
    	char[] buf = new char[1024];
    	int len;
    	while ((len = fr.read(buf)) != -1) {
    		System.out.print(new String(buf, 0, len));
    	}
    } catch (IOException e) {
    	System.out.println("read-Exception :" + e.getMessage());
    } finally {
    	if (fr != null) {
    		try {
    			fr.close();
    		} catch (IOException e) {
    			System.out.println("close-Exception :" + e.getMessage());
    		}
    	}
    }
    

2.5.2 写入文件

  1. 创建流对象,建立数据存放文件

    FileWriter fw = new FileWriter(new File(“Test.txt”));
    
  2. 调用流对象的写入方法,将数据写入流

    fw.write(“atguigu-songhongkang”);
    
  3. 关闭流资源,并将流中的数据清空到文件中。

    fw.close();
    

    示例:

    FileWriter fw = null;
    try {
    	fw = new FileWriter(new File("Test.txt"));
    	fw.write("atguigu-songhongkang");
    } catch (IOException e) {
    	e.printStackTrace();
    } finally {
    	if (fw != null)
    		try {
    			fw.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    	}
    }
    

2.5.3 注意点

  • 定义文件路径时,注意:可以用 “/” 或者 “\” 。
  • 在写入一个文件时,如果使用构造器 FileOutputStream(file),则目录目录下有同名文下有同名文
    件将被覆盖。
  • 如果使用构造器 FileOutputStream(file, true),则目录下的同名文件不会被覆盖,在文件内容末尾追加内容。
  • 在读取文件时,必须保证该文件已存在,否则报异常。
  • 字节流操作字节,比如:.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt。
  • 字符流操作字符,只能操作普通文本文件。最常见的文本文件:.txt,.java,.c,.cpp 等语言的源代码。尤其注意 .doc,.excel,.ppt 这些不是文本文件。

2.5.4 文件流测试

1. FileReader 读入数据的基本操作:将 hello.txt 文件内容读入程序中,并输出到控制台。

    @Test
    public void testFileReader() {
        FileReader fr = null;
        try {
            // 1.实例化 File 类的对象,指明要操作的文件
            File file = new File("hello.txt");    // 相较于当前 Module

            // 2.提供具体的流
            fr = new FileReader(file);

            // 3.数据的读入
            // read():返回读入的一个字符。如果达到文件末尾,返回 -1
            int data;
            while ((data = fr.read()) != -1) {
                System.out.print((char)data);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.流的关闭操作
            try {
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

	// FileReader 中使用 read(char[] cbuf) 读入数据
    // 对 read() 操作升级:使用 read 的重载方法
    @Test
    public void testFileReader1() throws IOException {
        FileReader fr = null;
        try {
            // 1.File 类的实例化
            File file = new File("hello.txt");

            // 2.FileReader 流的实例化
            fr = new FileReader(file);

            // 3.读入的操作
            // read(char[] cbuf):返回每次读入 cbuf 数组中的字符数。如果达到文件末尾,返回 -1。
            char[] cbuf = new char[5];
            int len;
            while ((len = fr.read(cbuf)) != -1) {
                // 方式一:
//                for (int i = 0; i < len; i++) {    // len 不能写成 cbuf.length
//                    System.out.print(cbuf[i]);
//                }

                // 方式二:
                String str = new String(cbuf, 0, len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fr != null) {
                try {
                    // 4.资源的关闭
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2. FileWriter 写出数据的操作:从内存中写出数据到硬盘文件里。

	/*
    说明:
    1.输出操作,对应的 File 可以不存在。并不会报异常。
    2.
        File 对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
        File 对应的硬盘中的文件如果存在:
            如果流使用的构造器是:FileWriter(file, false) / FileWriter(file):对原有的文件覆盖
            如果流使用的构造器是:FileWriter(file, true):不会对原有文件覆盖,二十在原有文件基础上追加内容
    */
    @Test
    public void testFileWriter() {
        FileWriter fw = null;
        try {
            // 1.提供 File 类的对象,指明写出到的文件
            File file = new File("hello1.txt");

            // 2.提供 FileWriter 的对象,用于数据的写出
            fw = new FileWriter(file, true);

            // 3.写出的操作
            fw.write("I have a dream!\n");
            fw.write("you need to have a dream!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.资源流的关闭
            if(fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

3. 使用 FileReader 和 FileWriter 实现文本文件的复制

    @Test
    public void testFileReaderFileWriter() throws IOException {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            // 1.创建 File 类的对象,指明读入和写出的文件
            // 注意:不能使用字符流来处理图片等字节数据
            File srcFile = new File("hello.txt");
            File destFile = new File("hello2.txt");

            // 2.创建输入流和输出流的对象
            fr = new FileReader(srcFile);
            fw = new FileWriter(destFile);

            // 3.数据的读入和写出操作
            char[] cbuf = new char[5];
            int len;    // 记录每次读入到 cbuf 数组中的字符数
            while ((len = fr.read(cbuf)) != -1) {
                // 每次写出 len 个字符
                fw.write(cbuf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭流资源
            try {
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

4. 使用 FileInputStream 不能读取文本文件的测试

    @Test
    // 使用字节流 FileInputStream 处理文本文件,可能出现乱码
    public void testFileInputStream() {
        FileInputStream fis = null;
        try {
            // 1.造文件
            File file = new File("hello.txt");

            // 2.造流
            fis = new FileInputStream(file);

            // 3.读数据
            byte[] buffer = new byte[5];
            int len;    // 记录每次读取的字节个数
            while ((len = fis.read(buffer)) != -1) {

                String str = new String(buffer, 0, len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                // 4.关闭资源
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

5. 使用 FileInputStream 和 FileOutputStream 读写非文本文件

    // 实现对图片的复制操作
    @Test
    public void testFileInputOutputStream() {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            //
            File srcFile = new File("image.jpg");
            File destFile = new File("image2.jpg");

            //
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);

            // 复制的过程
            byte[] buffer = new byte[5];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null) {
                //
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

6. 使用 FileputStream 和 FileOutputStream 复制文件的方法测试

 // 指定路径下文件的复制
    public void copyFile(String srcpath, String destpath) {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            //
            File srcFile = new File(srcpath);
            File destFile = new File(destpath);

            //
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);

            // 复制的过程
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null) {
                //
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void testCopyFile() {

        long start = System.currentTimeMillis();

        String srcPath = "C:\\Users\\Desktop\\01-视频.mp4";
        String destPath = "C:\\Users\\Desktop\\02-视频.mp4";
        copyFile(srcPath, destPath);

        long end = System.currentTimeMillis();

        System.out.println("复制操作花费的时间为:" + (end - start));

    }
}

2.6 缓冲流(处理流)

  • 为了提高数据读写的速度,Java API 提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用 8192 个字节 (8Kb) 的缓冲区。
private static int DEFAULT_BUFFER_SIZE = 8192;
  • 缓冲流要 “套接” 在相应的节点流之上,根据数据操作单位可以把缓冲流分为:

    • BufferedInputStream 和 BufferedOutputStream

    • BufferedReader 和 BufferedWriter

  • 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区。

  • 当使用BufferedInputStream读取字节文件时,BufferedInputStream 会一次性从文件中读取 8192 个 (8Kb) 存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个 8192 个字节数组。

  • 向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法 flush() 可以强制将缓冲区的内容全部写入输出流。

  • 关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,因为关闭外层流的的同时,内层流也会自动的进行关闭。所以关于内层流的关闭,我们可以省略。

  • flush() 方法的使用:刷新缓冲区,调用后缓冲区未满也直接写出,清空缓冲区。即:手动将 buffer 中内容写入文件。

  • 如果是带缓冲区的流对象的 close() 方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。

2.6.1 缓冲流的测试:

1. 缓冲流(字节型)实现非文本文件的复制

@Test
    public void BufferedStreamTest() {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            // 1. 造文件
            File srcFile = new File("image.jpg");
            File destFile = new File("image3.jpg");

            // 2. 造流
            // 2.1 造节点流
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(destFile);
            // 2.2 造缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            // 3. 复制的细节:读取、写入
            byte[] buffer = new byte[10];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);

//                bos.flush();    // 刷新缓冲区,调用后缓冲区未满也直接写出,清空缓冲区
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4. 资源关闭
            // 要求:先关闭外层的流,再关闭内层的流
            if(bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 说明:关闭外层流的的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略。
//        fos.close();
//        fis.close();
    }

2. 缓冲流(字符型)实现文本文件的复制

	/*
    使用 BufferedReader 和 BufferedWriter 实现文本文件的复制(言外之意:不能处理非文本文件)
     */
    @Test
    public void testBufferedReaderBufferedWriter() {
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            // 创建文件和相应的流:造文件,造节点流,造缓冲流合成一步
            br = new BufferedReader(new FileReader(new File("dbcp.txt")));
            bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));

            // 读写操作
            // 方式一:使用 char[] 数组
//            char[] cbuf = new char[1024];
//            int len;
//            while ((len = br.read(cbuf)) != -1) {
//                bw.write(cbuf, 0, len);
//    //            bw.flush();
//            }

            // 方式二:使用 String
            String data;
            while ((data = br.readLine()) != null) {
                // 方法一
//                bw.write(data + "\n");    // data 中不包含换行符

                // 方法二
                bw.write(data);
                bw.newLine();    // 提供换行的操作
            }


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.7 转换流(处理流)

  • 转换流提供了在字节流和字符流之间的转换。
  • Java API 提供了两个转换流:
    • InputStreamReader:将 InputStream 转换为 Reader。
    • OutputStreamWriter:将 Writer 转换为 OutputStream。
  • 当字节流中的数据都是字符时,转成字符流操作更高效。
  • 很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
    • 解码:字节、字节数组 → 字符数组、字符串
    • 编码:字符数组、字符串 → 字节、字节数组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vv3MI4h6-1640706447495)(D:\单宇楠\md文档\md插图\IO流5.jpg)]

InputStreamReader

实现将字节的输入流按指定字符集转换为字符的输入流。需要和 InputStream “套接”。

构造器:

  • public InputStreamReader(InputStream in)
  • public InputSreamReader(InputStream in, String charsetName)

charsetName 为字符集的名称,如:InputStreamReader isr = new InputStreamReader(fis, “UTF-8”);

OutputStreamWriter

实现将字符的输出流按指定字符集转换为字节的输出流。需要和 OutputStream “套接”。

构造器:

  • public OutputStreamWriter(OutputStream out)
  • public OutputSreamWriter(OutputStream out, String charsetName)

2.7.1 转换流的测试

InputStreamReader 的使用,实现字节的输入流到字符的输入流的转换

/*
 此时处理异常仍应该使用 try-catch-finally(偷懒写法)
 */
    @Test
    public void test1() throws IOException {
        FileInputStream fis = new FileInputStream("dbcp.txt");
//        InputStreamReader isr = new InputStreamReader(fis);    // 使用系统默认的字符集
        // 参数 2 指明了字符集,具体使用哪个字符集取决于文件 dbcp.txt 保存时使用的字符集
        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");

        char[] cbuf = new char[20];
        int len;
        while((len = isr.read(cbuf)) != -1) {
            String str = new String(cbuf, 0, len);
            System.out.print(str);
        }
        
        isr.close();
    }

转换流实现文件的读入和写出,综合使用 InputStreamReader 和 OutputStreamWriter

/*
此时处理异常仍应该使用 try-catch-finally(偷懒写法)
*/
    @Test
    public void test2() throws Exception {
        // 1.造文件、造流
        File file1 = new File("dbcp.txt");
        File file2 = new File("dbcp_gbk.txt");

        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);

        InputStreamReader isr = new InputStreamReader(fis, "utf-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");

        // 2.读写过程
        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1) {
            osw.write(cbuf, 0, len);
        }

        // 3.关闭资源
        isr.close();
        osw.close();
    }

2.8 标准输入、输出流(处理流)

在 java.lang.System 类中,定义了系统标准输入流 in 和 标准输出流 out。系统标准流在 Java 程序运行时会自动提供,标准输入流 System.in 将会读取键盘的输入,标准输出流将数据在控制台窗口中输出。

  • System.in 的类型是 InputStream。
  • System.out 的类型是 PrintStream,其是 OutputStream 的子类。

重定向:通过 System 类的 setIn,setOut 方法对默认设备进行改变。setIn(InputStream is) / setOut(PrintStream ps) 重新指定输入和输出的流。

  • public static void setIn(InputStream in)
  • public static void setOut(PrintStream out)

2.8.1 标准输入、输出流的测试

从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入 “e” 或者 “exit” 时,退出程序。

public static void main(String[] args) {
        BufferedReader br = null;
        try {
            InputStreamReader isr = new InputStreamReader(System.in);
            br = new BufferedReader(isr);

            while (true) {
                System.out.println("请输入字符串:");
                String data = br.readLine();
                 // 这种写法避免空指针
                if("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {   
                    System.out.println("程序结束");
                    break;
                }

                String upperCase = data.toUpperCase();
                System.out.println(upperCase);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.9 打印流(处理流)

实现将基本数据类型的数据格式转换为字符串输出。

打印流:PrintStream 和 PrintWriter

  • 提供了一系列重载的 print() 和 println() 方法,用于多种数据类型的输出。
  • PrintStream 和 PrintWriter 的输出不会抛出 IOException 异常。
  • PrintStream 和 PrintWriter 有自动 flush 功能。
  • PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
  • System.out 返回的是 PrintStream 的实例。

2.9.1 打印流的测试

将 ASCII 码打印到 D: \IO\text.txt 文件中。

PrintStream ps = null;
try {
    FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
    // 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
    ps = new PrintStream(fos, true);
    if (ps != null) {// 把标准输出流(控制台输出)改成文件
		System.setOut(ps);
	}
	//如果只有 for 循环中的内容,就是在控制台中打印 ASCII 码
	for (int i = 0; i <= 255; i++) { // 输出ASCII字符
		System.out.print((char) i);
		if (i % 50 == 0) { // 每50个数据一行
			System.out.println(); // 换行
		}
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} finally {
	if (ps != null) {
		ps.close();
	}
}

2.10 数据流(处理流)

为了方便地操作 Java 语言的基本数据类型和 String 的数据,可以使用数据流。

数据流有两个类:(用于读取和写出基本数据类型、String类的数据)

  • 数据输入流 DataInputStream 类,“套接” 在 InputStream 子类的流上。
  • 数据输出流 DataOutputStream 类,“套接” 在 OutputStream 子类的流上。

DataInputStream 中的常用方法:

  • boolean readBoolean()
  • byte readByte()
  • char readChar()
  • char readChar()
  • double readDouble()
  • short readShort()
  • long readLong()
  • int readInt()
  • String readUTF():返回使用 UTF-8 编码的字符串。

DataOutputStream 中的常用方法:

  • boolean writeBoolean()
  • byte writeByte()
  • char writeChar()
  • char writeChar()
  • double writeDouble()
  • short writeShort()
  • long writeLong()
  • int writeInt()
  • String writeUTF()

2.10.1 数据流的测试

将内存中的字符串、基本数据类型的变量写出到文件中。

@Test
    public void test3() throws IOException {    // 偷懒抛异常

        // 1.
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

        //2.
        dos.writeUTF("中国人");
//        dos.flush();    // 刷新操作,将内存中的数据写入文件
        dos.writeInt(18);
//        dos.flush();
        dos.writeBoolean(true);
//        dos.flush();

        //3.
        dos.close();
    }

将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。

@Test
public void test4() throws IOException {    // 偷懒抛异常

    // 注意:读取不同类型的数据的顺序要与当初写入文件时,保存的数据顺序一致。
    // 1.
    DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

    // 2.
    String name =  dis.readUTF();
    int age = dis.readInt();
    boolean isMale = dis.readBoolean();

    System.out.println("name = " + name);
    System.out.println("age = " + age);
    System.out.println("isMale = " + isMale);

    // 3.
    dis.close();

}

2.11 对象流(处理流)

对象流包括 ObjectInputStream 和 OjbectOutputSteam 。用于存储和读取基本数据类型或对象的处理流。它的强大之处就是可以把 Java 中的对象写入到数据源中,也能把对象从数据源中还原回来。

序列化与反序列化

  • 序列化:用 ObjectOutputStream 类保存基本类型数据或对象的机制。
  • 反序列化:用 ObjectInputStream 类读取基本类型数据或对象的机制。

注意:ObjectOutputStream 和 ObjectInputStream 不能序列化 static 和 transient 修饰的成员变量。

对象的序列化

对象序列化机制允许把内存中的 Java 对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的 Java 对象。序列化的好处在于可将任何实现了 Serializable 接口的对象转化为字节数据,使其在保存和传输时可被还原。

注意:如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出 NotSerializableException 异常。

  • Serializable
  • Externalizable

凡是实现 Serializable 接口的类都有一个表示序列化版本标识符的静态变量:private static final long serialVersionUID。serialVersionUID 用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象
进行版本控制,有关各版本反序列化时是否兼容。如果类没有显示定义这个静态常量,它的值是 Java 运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,
显式声明。

简单来说,Java 的序列化机制是通过在运行时判断类的 serialVersionUID 来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID 与本地相应实体类的 serialVersionUID 进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)

2.11.1 对象流的测试

对象流序列化与反序列化字符串操作

    /*
    序列化过程:将内存中的 java 对象保存到磁盘中或通过网络传输出去
    使用 ObjectOutputStream 实现
     */
    @Test
    public void testObjectOutputStream() {
        ObjectOutputStream oos = null;
        try {
            // 1.造流
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));

            // 2.造对象
            oos.writeObject(new String("我爱北京天安门"));
            oos.flush();    // 刷新操作

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(oos != null) {
                try {
                    // 3.关闭流
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    /*
    反序列化:将磁盘文件中的对象还原为内存中的一个 java 对象
    使用 ObjectInputStream 来实现
     */
    @Test
    public void testObjectInputStream() {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));

            Object obj = ois.readObject();
            String str = (String) obj;

            System.out.println(str);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

自定义类实现序列化与反序列化操作

若某个类实现了 Serializable 接口,该类的对象就是可序列化的:

  • 一个创建一个 ObjectOutputStream
  • 调用调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象
  • 注意写出一次,操作 flush() 一次

反序列化:

  • 创建一个 ObjectInputStream
  • 调用 readObject() 方法读取流中的对象

注意:如果某个类的属性不是基本数据类型或 String 类型,而是另一个引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的 Field 的类也不能序列化。

Person 类

/**
 * Person 需要满足如下要求,方可序列化
 * 1.需要实现接口:Serializable
 * 2.当前类提供一个全局常量:serialVersionUID
 * 3.除了当前 Person 类需要实现 Serializable 接口之外,还必须保证其内部所有属性也是可序列化的。   (默认情况下,基本数据类型是可序列化)
 
   注意:ObjectOutputStream 和 ObjectInputStream 不能序列化 static 和 transient 修饰的成员变量。
 */

public class Person implements Serializable {
    public static final long serialVersionUID = 435345324535L;

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

测试类

    // 序列化
    @Test
    public void testObjectOutputStream() {
        ObjectOutputStream oos = null;
        try {
            // 1.
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));

            // 2.
            oos.writeObject(new String("我爱北京天安门"));
            oos.flush();    // 刷新操作

            oos.writeObject(new Person("张三", 23));
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(oos != null) {
                try {
                    // 3.
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 反序列化
    @Test
    public void testObjectInputStream() {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));

            Object obj = ois.readObject();
            String str = (String) obj;

            Person p = (Person) ois.readObject();

            System.out.println(str);
            System.out.println(p);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.12 随机存取文件类(RandomAccessFile 类)

RandomAccessFile 声明在 java.io 包下,但直接继承于 java.lang.Object 类。并且它实现了 DataInput、DataOutput 这两个接口,也就意味着这个类既可以读也可以写。RandomAccessFile 类支持 “随机访问” 的方式,程序可以直接跳到文件的任意地方来读、写文件。

  • 支持只访问文件的部分内容。
  • 可以向已存在的文件后追加内容。

RandomAccessFile 对象包含一个记录指针,用以标示当前读写处的位置。

RandomAccessFile 类对象可以自由移动记录指针:

  • long getFilePointer():获取文件记录指针的当前位置。
  • void seek(long pos):将文件记录指针定位到 pos 位置。

构造器

  • public RandomAccessFile(File file, String mode)
  • public RandomAccessFile(String name, String mode)

创建 RandomAccessFile 类实例需要指定一个 mode 参数,该参数指定 RandomAccessFile 的访问模式:

  • r:以只读方式打开。
  • rw:打开以便读取和写入。
  • rwd:打开以便读取和写入;同步文件内容的更新。
  • rws:打开以便读取和写入;同步文件内容和元数据的更新。

如果模式为只读 r。则不会创建文件,而是会去读取一个已经存在的文件,如果读取的文件不存在则会出现异常。 如果模式为rw读写,如果文件不存在则会去创建文件,如果存在则不会创建。

2.12.1 随机存取文件类的测试

RandomAccessFile 实现数据的读写操作

/**
 * RandomAccessFile 的使用
 * 1.RandomAccessFile 直接继承于 java,lang.Object 类,实现了 DataInput 和 DataOutput 接口
 * 2.RandomAccessFile 既可以作为一个输入流,又可以作为一个输出流
 * 3.如果 RandomAccessFile 作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
 *   如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下从头覆盖)
 *
 * 4.可以通过相关的操作,实现 RandomAccessFile ”插入“数据的效果
 */
    @Test
    public void test1() throws FileNotFoundException {

        RandomAccessFile rad1 = null;
        RandomAccessFile rad2 = null;
        try {
            // 1.
            rad1 = new RandomAccessFile(new File("image.jpg"), "r");
            rad2 = new RandomAccessFile(new File("image1.jpg"), "rw");
            // 2.
            byte[] buffer = new byte[1024];
            int len;
            while((len = rad1.read(buffer)) != -1) {
                rad2.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 3.
            if(rad1 != null) {
                try {
                    rad1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(rad2 != null) {
                try {
                    rad2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void test2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hi.txt", "rw");

        raf1.write("xyz".getBytes());

        raf1.close();
    }

RandomAccessFile 实现数据的插入操作

/*
使用 RandomAccessFile 实现数据的插入效果
 */
    @Test
    public void test3() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hi.txt", "rw");

        raf1.seek(3);    // 将指针调到角标为 3 的位置

        // 保存指针 3 后面的所有数据到 StringBuilder 中
        StringBuilder builder = new StringBuilder((int) new File("hi.txt").length());    // 指定 builder 的长度
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1) {
            builder.append(new String(buffer, 0, len));
        }

        // 调回指针,写入 ”xyz“
        raf1.seek(3);
        raf1.write("xyz".getBytes());

        // 将 StringBuilder 中的数据写入到文件中
        raf1.write(builder.toString().getBytes());    // 先 toString 得到一个字符串
    }

3 字符编码集的说明

编码表的由来

计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

常见的编码表

  • ASCII:美国标准信息交换码。用一个字节的 7 位表示 128 个字符。
  • ISO-8859-1:拉丁码表。欧洲码表。用一个字节的 8 位表示,单字节编码,向下兼容 ASCII。
  • GB2312:信息交换用汉字编码字符集(中国的中文编码表)。最多两个字节编码所有字符。
  • GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码。GBK 等双字节编码方式,用最高位是 1 或 0 表示两个字节和一个字节。
  • Unicode:统一码,也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。Unicode 只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。推荐的 Unicode 编码是 UTF-8 和 UTF-16 。
  • UTF-8:为了提高 Unicode 的编码效率,于是就出现了 UTF-8 编码。变长的编码方式,UTF-8 可以根据不同的符号自动选择编码的长短。

4 Java NIO

4.1 Java NIO 概述

Java NIO (New IO,Non-Blocking IO) 是从 Java 1.4 版本开始引入的一套新的 IO API,可以替代标准的Java IO API。NIO 与原来的 IO 有同样的作用和目的,但是使用的方式完全不同,NIO 支持面向缓冲区的(IO 是面向流的)、基于通道的 IO 操作。NIO 将以更加高效的方式进行文件的读写操作。

Java API 中提供了两套 NIO,一套是针对标准输入输出 NIO,另一套就是网络编程 NIO。

  • java.nio.channels.Channel
    • FileChannel:处理本地文件
    • SocketChannel:TCP 网络编程的客户端的 Channel
    • ServerSocketChannel:TCP 网络编程的服务器端的 Channel
    • DatagramChannel:UDP 网络编程中发送端和接收端的 Channel

随着 JDK 7 的发布,Java 对 NIO 进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为 NIO.2。因为 NIO 提供的一些功能,NIO 已经成为文件处理中越来越重要的部分。

4.2 Path、Paths 和 Files 核心 API

早期的 Java 只提供了一个 File 类来访问文件系统,但 File 类的功能比较有限,所提供的方法性能也不高。而且大多数方法在出错时仅返回失败,并不会提供异常信息。NIO. 2 为了弥补这种不足,引入了 Path 接口,代表一个平台无关的平台路径,描述了目录结构中文件的位置。Path 可以看成是 File类 的升级版本,实际引用的资源也可以不存在。

在以前 IO 操作都是这样写的:

import java.io.File;
File file = new File("index.html");

但在 Java 7 中,可以这样写:

import java.nio.file.Path; 
import java.nio.file.Paths; 
Path path = Paths.get("index.html");

同时,NIO.2 在 java.nio.file 包下还提供了 Files、Paths 工具类,Files 包含了大量静态的工具方法来操作文件;Paths 则包含了两个返回 Path 的静态工厂方法。

Paths 类提供的静态 get() 方法用来获取 Path 对象:

  • static Path get(String first, String … more):用于将多个字符串串连成路径。
  • static Path get(URI uri):返回指定 uri 对应的 Path 路径。
Path 接口

Path 常用方法:

  • String toString():返回调用 Path 对象的字符串表示形式 。
  • boolean startsWith(String path):判断是否以 path 路径开始。
  • boolean endsWith(String path):判断是否以 path 路径结束。
  • boolean isAbsolute():判断是否是绝对路径。
  • PathgetParent():返回 Path 对象包含整个路径,不包含 Path 对象指定的文件路径。
  • Path getRoot():返回调用 Path 对象的根路径。
  • Path getFileName():返回与调用 Path 对象关联的文件名。
  • int getNameCount():返回 Path 根目录后面元素的数量。
  • Path getName(int idx):返回指定索引位置 idx 的路径名称。
  • Path toAbsolutePath():作为绝对路径返回调用 Path 对象。
  • Path resolve(Pathp):合并两个路径,返回合并后的路径对应的 Path 对象
  • File toFile():将 Path 转化为 File 类的对象。
Files 类

java.nio.file.Files 用于操作文件或目录的工具类。

Files 常用方法:

  • Path copy(Path src,Path dest,CopyOption … how):文件的复制。
  • Path createDirectory(Path path, FileAttribute<?>… attr):创建一个目录。
  • Path createFile(Path path, FileAttribute<?>… arr):创建一个文件。
  • void delete(Path path):删除一个文件/目录,如果不存在,执行报错。
  • void deletelfExists(Path path):Path 对应的文件/目录如果存在,执行删除
  • Path move(Path src,Path dest,CopyOption…how):将 src 移动到 dest 位置。
  • long size(Path path):返回 path 指定文件的大小。

Files 常用方法:用于判断

  • boolean exists(Path path, LinkOption … opts) :判断文件是否存在。
  • boolean isDirectory(Path path, LinkOption … opts):判断是否是目录。
  • boolean isRegularFile(Path path, LinkOption … opts):判断是否是文件。
  • boolean isHidden(Path path):判断是否是隐藏文件。
  • boolean isReadable(Path path):判断文件是否可读。
  • boolean isWritable(Path path):判断文件是否可写。
  • boolean notExists(Path path, LinkOption … opts):判断文件是否不存在。

Files 常用方法:用于操作内容

  • SeekableByteChannel newByteChannel(Path path, OpenOption…how):获取与指定文件的连接,how 指定打开方式。
  • DirectoryStream newDirectoryStream(Path path):打开 path 指定的目录。
  • InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象。
  • OutputStream newOutputStream(Path path, OpenOption…how):获取 OutputStream 对象。
    调用 Path 对象的根路径。
  • Path getFileName():返回与调用 Path 对象关联的文件名。
  • int getNameCount():返回 Path 根目录后面元素的数量。
  • Path getName(int idx):返回指定索引位置 idx 的路径名称。
  • Path toAbsolutePath():作为绝对路径返回调用 Path 对象。
  • Path resolve(Pathp):合并两个路径,返回合并后的路径对应的 Path 对象
  • File toFile():将 Path 转化为 File 类的对象。
Files 类

java.nio.file.Files 用于操作文件或目录的工具类。

Files 常用方法:

  • Path copy(Path src,Path dest,CopyOption … how):文件的复制。
  • Path createDirectory(Path path, FileAttribute<?>… attr):创建一个目录。
  • Path createFile(Path path, FileAttribute<?>… arr):创建一个文件。
  • void delete(Path path):删除一个文件/目录,如果不存在,执行报错。
  • void deletelfExists(Path path):Path 对应的文件/目录如果存在,执行删除
  • Path move(Path src,Path dest,CopyOption…how):将 src 移动到 dest 位置。
  • long size(Path path):返回 path 指定文件的大小。

Files 常用方法:用于判断

  • boolean exists(Path path, LinkOption … opts) :判断文件是否存在。
  • boolean isDirectory(Path path, LinkOption … opts):判断是否是目录。
  • boolean isRegularFile(Path path, LinkOption … opts):判断是否是文件。
  • boolean isHidden(Path path):判断是否是隐藏文件。
  • boolean isReadable(Path path):判断文件是否可读。
  • boolean isWritable(Path path):判断文件是否可写。
  • boolean notExists(Path path, LinkOption … opts):判断文件是否不存在。

Files 常用方法:用于操作内容

  • SeekableByteChannel newByteChannel(Path path, OpenOption…how):获取与指定文件的连接,how 指定打开方式。
  • DirectoryStream newDirectoryStream(Path path):打开 path 指定的目录。
  • InputStream newInputStream(Path path, OpenOption…how):获取 InputStream 对象。
  • OutputStream newOutputStream(Path path, OpenOption…how):获取 OutputStream 对象。


这篇关于【Java】IO 流的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程