目 录CONTENT

文章目录

从0开始学Java——File类和IO流(15)

Eric
2022-01-23 / 0 评论 / 0 点赞 / 197 阅读 / 8,451 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-12-12,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1 File类

1.1 概述

  • FIle类是java.io包下代表和平台无关的文件和目录,换言之,如果希望在程序中操作文件和目录都可以使用File类来完成,File类能新建、删除、重命名文件和目录。

  • 在API中File的解释是文件和目录路径名的抽象表示形式,即File类是文件或目录的路径,而不是文件本身,因此File类不能直接访问文件内容本身,如果需要访问文件内容本身,就需要使用IO流了。

  • File类代表磁盘或网络中某个文件或目录的路径名称,例如:c:/美女.jpg

  • 不能直接通过File对象读取和写入数据,如果要操作数据,需要IO流。

1.2 File的构造方法

  • 通过将给定的路径名称字符串转换为抽象路径名为创建新的File实例:
public File(String pathname) {}
  • 通过父路径名字符串和子路径名字符串创建新的File实例:
public File(String parent, String child) {}
  • 通过父路径名和子路径名字符串创建新的File实例:
public File(File parent, String child) {}
  • 通过将给定的 file: URI到一个抽象路径名创建一个新的File实例:
public File(URI uri) {}
  • 示例:
package top.open1024.file.demo1;

import java.io.File;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 08:25
 */
public class Test {
    public static void main(String[] args) {
        // 通过将给定的路径名称字符串转换为抽象路径名为创建新的File实例
        File file = new File("D:\\develop\\Java\\jdk1.8.0_131\\bin\\javac.exe");
        System.out.println("file = " + file);
    }
}
  • 示例:
package top.open1024.file.demo2;

import java.io.File;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 08:30
 */
public class Test {
    public static void main(String[] args) {
        // 通过父路径名字符串和子路径名字符串创建新的File实例
        File file = new File("D:\\develop\\Java\\jdk1.8.0_131\\bin", "javac.exe");
        System.out.println("file = " + file);
    }
}
  • 示例:
package top.open1024.file.demo3;

import java.io.File;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 08:31
 */
public class Test {
    public static void main(String[] args) {
        File parent = new File("D:\\develop\\Java\\jdk1.8.0_131\\bin");
        String child = "javac.exe";
        File file = new File(parent, child);
        System.out.println("file = " + file);
    }
}
  • 示例:
package top.open1024.file.demo4;

import java.io.File;
import java.net.URI;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 08:33
 */
public class Test {
    public static void main(String[] args) {
        URI uri = URI.create("file:///D:/develop/Java/jdk1.8.0_131/bin/javac.exe");
        File file = new File(uri);
        System.out.println("file = " + file);
    }
}

1.3 File的常用方法

1.3.1 获取文件和目录基本信息的方法

  • 返回由此File表示的文件或目录的名称:
public String getName() {}
  • 返回由此File表示的文件的长度:
ublic long length() {}
  • 将此File转换为路径名字符串:
public String getPath() {}
  • 示例:
package top.open1024.file.demo5;

import java.io.File;
import java.time.Instant;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 08:54
 */
public class Test {
    public static void main(String[] args) {
        File file = new File("D:\\develop\\Java\\jdk1.8.0_131\\bin\\javac.exe");

        // 返回由此File表示的文件或目录的名称
        String name = file.getName();
        System.out.println("name = " + name); // name = javac.exe

        // 返回由此File表示的文件的长度
        long length = file.length();
        System.out.println("length = " + length); // length = 15904

        // 将此File转换为路径名字符串
        String path = file.getPath();
        System.out.println("path = " + path); // path = D:\develop\Java\jdk1.8.0_131\bin\javac.exe

        long lastModified = file.lastModified();
        System.out.println("lastModified = " + lastModified); // lastModified = 1626956893615
    }
}

1.3.2 路径

  • 将此File实例转换为路径名称字符串:
public String getPath() {}
  • 返回此File实例的绝对路径名字符串:
public String getAbsolutePath() {}
  • 返回此File实例所对应的规范路径名:
public String getCanonicalPath() throws IOException {}
  • 示例:
package top.open1024.file.demo6;

import java.io.File;
import java.io.IOException;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 09:16
 */
public class Test {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\develop\\Java\\jdk1.8.0_131\\bin\\javac.exe");

        // 将此File实例转换为路径名称字符串
        String path = file.getPath();
        System.out.println("path = " + path); // D:\develop\Java\jdk1.8.0_131\bin\javac.exe

        // 返回此File实例的绝对路径名字符串
        String absolutePath = file.getAbsolutePath();
        System.out.println("absolutePath = " + absolutePath); // D:\develop\Java\jdk1.8.0_131\bin\javac.exe

        // 返回此File实例所对应的规范路径名
        String canonicalPath = file.getCanonicalPath();
        System.out.println("canonicalPath = " + canonicalPath); // D:\develop\Java\jdk1.8.0_131\bin\javac.exe
    }
}

1.3.3 判断功能的方法

  • 判断File实例表示的文件或目录是否存在:
public boolean exists() {}
  • 判断File实例表示的是否是文件:
public boolean isFile() {
  • 判断File实例表示的是否是目录:
public boolean isDirectory() {}
  • 判断File构造方法中的路径是否是绝对路径:
public boolean isAbsolute() {}
  • 示例:
package top.open1024.file.demo7;

import java.io.File;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 09:23
 */
public class Test {
    public static void main(String[] args) {
        File file = new File("D:\\develop\\Java\\jdk1.8.0_131\\bin\\javac.exe");

        boolean exists = file.exists();
        System.out.println("exists = " + exists); // exists = true

        boolean flag = file.isFile();
        System.out.println("flag = " + flag); // flag = true

        flag = file.isDirectory();
        System.out.println("flag = " + flag); // flag = false

        boolean absolute = file.isAbsolute();
        System.out.println("absolute = " + absolute); // absolute = true

    }
}

1.3.4 创建和删除的方法

  • 当且仅当具有该名称的文件尚不存在时,创建一个新的空文件:
public boolean createNewFile() throws IOException {}
  • 删除由此File表示的文件或目录(只能删除空目录):
public boolean delete() {}
  • 创建由此File表示的目录:
public boolean mkdir() {}
  • 创建由此File表示的目录(包含父目录):
public boolean mkdirs() {}
  • 示例:
package top.open1024.file.demo8;

import java.io.File;
import java.io.IOException;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 09:45
 */
public class Test {
    public static void main(String[] args) throws IOException {
        // 文件的创建
        File file = new File("aaa.txt");
        System.out.println("是否存在:" + file.exists()); // 是否存在:false
        System.out.println("是否创建:" + file.createNewFile()); // 是否创建:true
        System.out.println("是否存在:" + file.exists()); // 是否存在:true

        // 目录的创建
        File file2 = new File("newDir");
        System.out.println("是否存在:" + file2.exists()); // 是否存在:false
        System.out.println("是否创建:" + file2.mkdir()); // 是否创建:true
        System.out.println("是否存在:" + file2.exists()); // 是否存在:true

        // 创建多级目录
        File file3 = new File("newDira/newDirb");
        System.out.println("是否存在:" + file3.exists()); // 是否存在:false
        System.out.println("是否创建:" + file3.mkdirs()); // 是否创建:true
        System.out.println("是否存在:" + file3.exists()); // 是否存在:true

        // 文件的删除
        System.out.println(file.delete()); // true

        // 目录的删除
        System.out.println(file2.delete()); // true
        System.out.println(file3.delete()); // true

    }
}

1.4 递归实现多级目录操作

1.4.1 相关方法

  • 返回一个String数组,表示该File目录中的所有子文件或目录:
public String[] list() {}
  • 返回一个File数组,表示该File目录中的所有的子文件或目录:
public File[] listFiles() {}
  • 返回所有满足指定过滤器的文件和目录的String数组:
public String[] list(FilenameFilter filter) {}
  • 返回所有满足指定过滤器的文件和目录的File数组:
public File[] listFiles(FilenameFilter filter) {}

1.4.2 递归打印多级目录

  • 分析:多级目录的打印。遍历之前,无从知道到底有多少级目录,所以我们可以使用递归实现。

  • 示例:

package top.open1024.file.demo9;

import java.io.File;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 15:45
 */
public class Test {
    public static void main(String[] args) {
        print(new File("D:\\develop\\Java\\jdk1.8.0_131"));
    }

    public static void print(File file) {
        if (null != file && file.isDirectory()) {
            File[] files = file.listFiles();
            if (null != files) {
                for (File f : files) {
                    print(f);
                }
            }
        }
        System.out.println(file);
    }
}

1.4.3 递归打印某目录下(包括子目录)中所有满足条件的文件

  • 示例:列出所有".java"文件
package top.open1024.file.demo10;

import java.io.File;
import java.io.FilenameFilter;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-03 16:12
 */
public class Test {
    public static void main(String[] args) {
        print(new File("D:\\project\\java-core"));
    }

    public static void print(File file) {
        if (null != file && file.isDirectory()) {
            File[] files = file.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return name.endsWith(".java") || new File(dir, name).isDirectory();
                }
            });
            if (null != files) {
                for (File f : files) {
                    if (f.isFile()) {
                        System.out.println(f);
                    }
                    print(f);
                }
            }
        }
    }
}

2 IO流

2.1 概述

  • I/O是Input和Output的缩写,IO技术是非常实用的技术,用于处理设备之间的数据传输,如:读写文件、网络通讯等。

  • Java程序中,对于数据的输入/输出操作以流stream的方式进行。

  • java.io包下提供了各种“流”类和接口,用于获取不同种类的数据,并通过标准的方法输入或输出数据。

2.2 Java IO原理

  • 输入(Input):读取外部数据(磁盘、U盘等存储设备的数据)到程序(内存)中。

  • 输出(Output):将程序(内存)数据输出到磁盘、U盘等存储设备中。

img

2.3 IO的分类

  • 根据流的流向分类:

    • 输入流:将数据从其他设备上读取到内存中的流。以InputStream、Reader结尾。
    • 输出流:将数据从内存中写出到其他设备上的流。以OutputStream和Writer结尾。
  • 根据数据的类型分类:

    • 字节流:以字节为单位,读写数据的流。以InputStream和OutputStream结尾。
    • 字符流:以字符为单位,读写数据的流。以Reader和Writer结尾。
  • 根据IO刘的角色不同分类:

    • 节点流:可以从或向一个特定的地方(节点)读取数据。如FileReader。
    • 处理流:对一个已经存在的流进行连接和封装,通过锁封装的流的功能实现数据读写。如:BufferReader,处理流的构造方法总是要带一个其它的流对象做参数。一个流对象经过多次其它流的多次包装,称为流的链接。
  • 常用的节点流:

    • 文件:FileInputStream、FileOutputStrean、FileReader、FileWriter文件进行处理的节点流。
    • 字符串:StringReader、StringWriter对字符串进行处理的节点流。
    • 数组: ByteArrayInputStream、ByteArrayOutputStream、CharArrayReader、CharArrayWriter对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
    • 管道:PipedInputStream、PipedOutputStream、PipedReader、PipedWriter对管道进行处理的节点流。
  • 常用处理流:

    • 缓冲流:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter---增加缓冲功能,避免频繁读写硬盘。
    • 转换流:InputStreamReader、OutputStreamReader---实现字节流和字符流之间的转换。
    • 数据流:DataInputStream、DataOutputStream -提供读写Java基础数据类型功能。
    • 对象流:ObjectInputStream、ObjectOutputStream--提供直接读写Java对象功能。

2.4 四大顶级抽象流父类

输入流输出流
字节流字节输入流InputStream字节输出流OutputStream
字符流字符输入流Reader字符输出流Writer

2.5 字节流

2.5.1 概述

  • 一切文件数据(文本、图片、视频等)在存储的时候,都是以二进制的形式保存的,都是一个个的字节;同样,在传输的时候依然如此。所以,字节流可以传输任意文件数据。

  • 在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输始终是二进制数据。

2.5.3 OutputStream

  • java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息输出的目的地。它定义了字节输出流的基本共性的功能方法。

  • 写入单个字节:

public abstract void write(int b) throws IOException;
  • 写入字节数组:
public void write(byte b[]) throws IOException {}
  • 写入字节数组的一部分,从offset开始,一共len个:
public void write(byte b[], int off, int len) throws IOException {}
  • 刷新流:
public void flush() throws IOException {}
  • 关闭流:
public void close() throws IOException {}

注意:当完成流的操作的时候,必须调用close()方法,释放系统资源。

2.5.4 FileOutputStream

  • FileOutputStream是OutputStream的子类,FileOutputStream是文件输出流,用于将数据写出到文件中。

  • 构造方法:

  • 创建文件输出流以写入由指定的 File对象表示的文件:

public FileOutputStream(File file) throws FileNotFoundException {}
  • 创建文件输出流以指定的名称写入文件:
public FileOutputStream(String name) throws FileNotFoundException {}

注意:当创建FileOutputStream流对象的时候,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件;如果有这个文件,会覆盖这个文件的数据。

  • 数据追加:

  • 创建文件输出流以写入由指定的 File对象表示的文件:

public FileOutputStream(String name, boolean append)
      throws FileNotFoundException
  {}
  • 创建文件输出流以指定的名称写入文件:
public FileOutputStream(File file, boolean append)
      throws FileNotFoundException
  {}
  • 换行写出:windows系统中的换行符号是\r\n

  • 示例:写出单个字节

package top.open1024.io.demo1;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 06:04
 */
public class Test {
    public static void main(String[] args) {
        OutputStream os = null;
        try {
            // 使用文件名称创建流对象
            os = new FileOutputStream("d:/demo.txt");
            // 注意:虽然参数为int类型的四个字节,但是只会保留一个字节的信息写出
            os.write(97); // 写出第1个字节
            os.write(98); // 写出第2个字节
            os.write(99); // 写出第3个字节
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != os) {
                try {
                    // 关闭资源
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 示例:写出字节数组
package top.open1024.io.demo2;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 06:44
 */
public class Test {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        OutputStream os = new FileOutputStream("d:/demo.txt");
        os.write("open1024".getBytes(StandardCharsets.UTF_8));
        // 关闭资源
        os.close();
    }
}
  • 示例:写出指定长度的字节数组
package top.open1024.io.demo3;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 06:53
 */
public class Test {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        OutputStream os = new FileOutputStream("d:/demo.txt");
        os.write("abcd".getBytes(StandardCharsets.UTF_8), 2, 1);
        // 关闭资源
        os.close();
    }
}
  • 示例:数据追加
package top.open1024.io.demo4;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 06:59
 */
public class Test {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象,append为true,表示追加写出
        OutputStream os = new FileOutputStream("d:/demo.txt", true);
        os.write("abcd".getBytes(StandardCharsets.UTF_8), 1, 3);
        // 关闭资源
        os.close();
    }
}
  • 示例:换行写出
package top.open1024.io.demo5;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 07:02
 */
public class Test {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象,append为true,表示追加写出
        OutputStream os = new FileOutputStream("d:/demo.txt", true);
        char[] chs = {'a', 'b', 'c', 'd'};
        for (char ch : chs) {
            os.write(ch);
            os.write("\r\n".getBytes());
        }
        // 关闭资源
        os.close();
    }
}

2.5.5 IO异常处理

  • 示例:
package top.open1024.io.demo1;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 06:04
 */
public class Test {
    public static void main(String[] args) {
        OutputStream os = null;
        try {
            // 使用文件名称创建流对象
            os = new FileOutputStream("d:/demo.txt");
            // 注意:虽然参数为int类型的四个字节,但是只会保留一个字节的信息写出
            os.write(97); // 写出第1个字节
            os.write(98); // 写出第2个字节
            os.write(99); // 写出第3个字节
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != os) {
                try {
                    // 关闭资源
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • JDK7的新特性try-with-resources:
try(需要关闭的资源对象的声明){
    业务逻辑代码
}catch(异常类型 e){
    处理异常代码
}catch(异常类型 e){
    处理异常代码
}
  • 没有finally,也不需要程序员去关闭资源对象,无论是否发生异常,都会关闭资源对象。

  • 实现了AutoCloseable或Closeable接口的类才可以自动进行资源关闭。

  • 示例:JDK7的新特性try-with-resources

package top.open1024.io.demo6;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 07:22
 */
public class Test {
    public static void main(String[] args) {
        // 使用文件名称创建流对象,append为true,表示追加写出
        try (OutputStream os = new FileOutputStream("d:/demo.txt", true)) {
            char[] chs = {'a', 'b', 'c', 'd'};
            for (char ch : chs) {
                os.write(ch);
                os.write("\r\n".getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.5.6 InputStream

  • InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

  • 读取单个字节:

  public abstract int read() throws IOException;
  • 读取字节数组:
  public int read(byte b[]) throws IOException {}
  • 读取字节数组,从offset开始,len长度:
public int read(byte b[], int off, int len) throws IOException {}
  • 关闭流:
public void close() throws IOException {}

2.5.7 FileInputStream

  • java.io.FileInputStream类是文件输入流,从文件中读取字节。

  • 构造方法:

  • 通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名:

public FileInputStream(File file) throws FileNotFoundException {}
  • 通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文件系统中的路径名name命名:
public FileInputStream(String name) throws FileNotFoundException {}
  • 示例:读取单个字节,读取到文件末尾,返回-1
package top.open1024.io.demo7;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 16:05
 */
public class Test {
    public static void main(String[] args) {
        try (InputStream is = new FileInputStream("d:/demo.txt")) {
            int len;
            while ((len = is.read()) != -1) {
                System.out.println((char)len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 示例:读取字节数组,读取到文件末尾,返回-1
package top.open1024.io.demo8;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 16:13
 */
public class Test {
    public static void main(String[] args) {
        try (InputStream is = new FileInputStream("d:/demo.txt")) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = is.read(bytes)) != -1) {
                System.out.println(new String(bytes, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.5.8 文件复制

  • 文件复制的本质是字节的搬家。

img

  • 示例:
package top.open1024.io.demo9;

import java.io.*;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 19:46
 */
public class Test {
    public static void main(String[] args) {
        try (InputStream is = new FileInputStream("C:\\Users\\xudaxian\\Pictures\\枪械少女.jpg");
            OutputStream os = new FileOutputStream("C:\\Users\\xudaxian\\Pictures\\枪械少女1.jpg")) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = is.read(bytes)) != -1) {
                os.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.6 字符流

2.6.1 概述

  • 当使用字节流读取文本文件的时候,可能会有一个小问题:就是遇到中文字符的时候,可能显示不完整,那是因为一个中文字符可能占用多个字节存储。所以,Java提供了一些字符流,以字符为单位读写数据,专门用于处理文本文件。

2.6.2 Reader

  • java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • 关闭此流并释放与此流相关联的任何系统资源:

abstract public void close() throws IOException;
  • 读取一个字符:
public int read() throws IOException
  • 读取字符数组:
public int read(char cbuf[]) throws IOException {}
  • 读取从offset索引开始,len长度的字符数组:
abstract public int read(char cbuf[], int off, int len) throws IOException;

2.6.3 FileReader

  • java.io.FileReader类是读取字符文件的类。构造的时候使用系统默认的字符编码和默认字节缓冲区。

字符编码:字节和字符的对应规范。windows系统的中文编码默认是GBK。

  • 构造方法:

  • 创建一个新的FileReader,给定要读取的File对象:

public FileReader(File file) throws FileNotFoundException {}
  • 创建一个新的FileReader,给定要读取的文件的名称:
public FileReader(String fileName) throws FileNotFoundException {}
  • 示例:读取单个字符
package top.open1024.io.demo11;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 21:58
 */
public class Test {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("d:/demo.txt")) {
            int b;
            while ((b = reader.read()) != -1) {
                System.out.println((char)b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 示例:读取字符数组
package top.open1024.io.demo12;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 08:37
 */
public class Test {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("d:/demo.txt")) {
            char[] buffer = new char[1024];
            int len;
            while ((len = reader.read(buffer)) != -1) {
                System.out.println(new String(buffer, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.6.4 Writer

  • java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地,它定义了字符输出流的基本共性功能方法。

  • 写入单个字符:

public void write(int c) throws IOException {}
  • 写入字符数组:
public void write(char cbuf[]) throws IOException {}
  • 写入从offset索引开始,len长度的字符数组:
abstract public void write(char cbuf[], int off, int len) throws IOException;
  • 写入字符串:
public void write(String str) throws IOException {}
  • 写入从offset索引开始,len长度的字符串:
public void write(String str, int off, int len) throws IOException {}
  • 刷新流:
abstract public void flush() throws IOException;
  • 关闭流:
abstract public void close() throws IOException;

2.6.5 FileWriter

  • java.io.FileWriter类是写出字符到文本的类。构造的时候使用系统默认的字符编码和默认字节缓冲区。

  • 构造方法:

  • 创建一个新的FileWriter,给定要读取的File对象:

public FileWriter(String fileName) throws IOException {}
  • 创建一个新的FileWriter,给定要读取的文件的名称:
public FileWriter(File file) throws IOException {}
  • 创建一个新的FileWriter,给定要读取的File对象,追加内容:
public FileWriter(String fileName, boolean append) throws IOException {}
  • 创建一个新的FileWriter,给定要读取的文件的名称,追加内容:
public FileWriter(File file, boolean append) throws IOException {}
  • 示例:写出单个字符
package top.open1024.io.demo13;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 08:48
 */
public class Test {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("d:/demo.txt")) {
            writer.write(97);
            writer.write('a');
            writer.write('b');
            writer.write('c');
            writer.write('许');
            writer.write('大');
            writer.write('仙');
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 示例:写出字符数组
package top.open1024.io.demo14;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 08:50
 */
public class Test {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("d:/demo.txt")) {
            writer.write("open1024".toCharArray());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 示例:写出字符串
package top.open1024.io.demo15;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 08:50
 */
public class Test {
    public static void main(String[] args) {
        try (Writer writer = new FileWriter("d:/demo.txt")) {
            writer.write("open1024");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.7 缓冲流

2.7.1 概述

  • 缓冲流,也叫高效流,按照数据类型分类:

    • 字节缓冲流:BufferedOutputStream、BufferedInputStream。
    • 字符缓冲流:BufferedReader、BufferedWriter。
  • 缓冲流会在内部创建一个缓冲区数组,缺省使用8192个字节(8kb)的缓冲区。

public class BufferedInputStream extends FilterInputStream {
   private static int DEFAULT_BUFFER_SIZE = 8192;
   ... 
}
  • 缓冲流的基本原理:

    • 当读取数据的时候,数据按块读入缓冲区,其后的读操作则直接访问缓冲区。
    • 当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性的从文件中读取8192个,存储在缓冲区中,直到缓冲区中装满了,才重新从文件中读取下一个8192个字节数组。
    • 向流中写入字节的时候,不会直接写到文件中,先写到缓冲区中直到缓冲区中写满,BufferedOutputStream才会将缓冲区中的数据一次性的写到文件里。使用flush()方法可以强制将缓冲区的内容全部写入输出流。

img

  • 关闭流的顺序和打开流的顺序相反,只需要关闭最外层流即可,因为关闭最外层流的同时也会关闭对应的内层流。

  • flush()方法的使用:手动将buffer中内容写入文件。

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

2.7.2 字节缓冲流

  • BufferedOutputStream的构造方法:
public BufferedOutputStream(OutputStream out) {}
  • BufferedInputStream的构造方法:
public BufferedInputStream(InputStream in) {}
  • 示例:
package top.open1024.io.demo10;

import java.io.*;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-04 21:45
 */
public class Test {
    public static void main(String[] args) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:/demo.txt"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:/test.txt"))) {
            byte[] bytes = new byte[1024];
            int len;
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.7.3 字符缓冲流

  • BufferedReader的构造方法:
public BufferedReader(Reader in) {}
  • BufferedReader的特殊方法读取一行:
public String readLine() throws IOException {}
  • BufferedWriter的构造方法:
public BufferedWriter(Writer out) {}
  • BufferedWriter的特殊方法写入换行符:
public void newLine() throws IOException {}
  • 示例:
package top.open1024.io.demo18;

import java.io.*;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 14:55
 */
public class Test {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("d:/demo.txt"));
            BufferedWriter writer = new BufferedWriter(new FileWriter("d:/test.txt"))) {
            char[] buffer = new char[1024];
            int len;
            while ((len = reader.read(buffer)) != -1) {
                writer.write(new String(buffer, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.8 转换流

2.8.1 字符编码

  • 计算机中存储的信息都是使用二进制表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。

  • 按照某种规则,将字符存储到计算机中,称为编码

  • 按照某种规则,将存储在计算机中的二进制数据解析并显示出来,称为解码

  • 例如:

    • 按照A规则存储,同样按照A规则解析,那么就能正确的显示文本符号。
    • 按照A规则存储,按照B规则解析,就会导致乱码现象。
  • 字符编码(CharacterEncoding):就是一套自然语言的字符和二进制数之间的对应规则。

  • 编码表:生活中的文字和计算机中二进制的对应规则。

2.8.2 字符集

  • 字符集(Charset):也称为编码表,是一个系统支持的所有字符集合,包括各个国家文字、标点符号、图形符号、数字等。

  • 计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见的字符集有:ASCII字符集、CBK字符集、Unicode字符集等等。

img

  • 可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。

2.8.3 概述

  • 转换流提供了在字节流和字符流之间的转换。

  • Java API提供了两个转换流:

    • InputStreamReader:将InputStream转换为Reader。
    • OutputStreamWriter:将Writer转换为OutputStream。
  • 字节流中的数据都是字符时,转换为字符流操作更加高效。

  • 很多时候,我们使用转换流来处理文件乱码问题,实现编码和解码的功能。

img

2.8.4 InputStreamReader

  • 转换流java.io.InputStreamReader是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定额字符集将其解码为字符。它的字符集可以有名称指定,也可以接受平台的默认字符集。

  • 构造方法:

  • 创建一个使用默认字符集的字符流:

public InputStreamReader(InputStream in) {}
  • 创建一个指定字符集的字符流:
public InputStreamReader(InputStream in, Charset cs) {}
  • 示例:
package top.open1024.io.demo17;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 10:56
 */
public class Test {
    public static void main(String[] args) {
        try (InputStreamReader reader =
            new InputStreamReader(new FileInputStream("d:/demo.txt"), StandardCharsets.UTF_8)) {
            char[] chs = new char[1024];
            int len;
            while ((len = reader.read(chs)) != -1) {
                System.out.println(new String(chs, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.8.5 OutputStreamWriter

  • 转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

  • 构造方法:

  • 创建一个使用默认字符集的字符流:

public OutputStreamWriter(OutputStream out) {}
  • 创建一个指定字符集的字符流:
public OutputStreamWriter(OutputStream out, Charset cs) {}
  • 示例:
package top.open1024.io.demo16;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 10:41
 */
public class Test {
    public static void main(String[] args) {
        try (OutputStreamWriter writer =
            new OutputStreamWriter(new FileOutputStream("d:/demo.txt"), StandardCharsets.UTF_8)) {
            writer.write("open1024,你好啊");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.9 打印流

  • 字节输出流:PrintStream。

  • 字符输出流:PrintWriter。

  • 打印流的特点:

    • ① 打印流负责输出打印,不关心数据源。
    • ② 提供了一系列重载的print()或println()方法,用于多种数据类型的输出。
    • ③ 打印流永远不会抛出IOException。
    • ④ 打印流具有自动刷新的功能:
      • 构造方法的第一个参数必须是IO流对象,第二个参数是true。
public PrintStream(OutputStream out, boolean autoFlush) {}
      • 必须调用println()、printf()、format()中的其中一个,才会启用自动刷新。
    • ⑤ System.out返回的是PrintStream的实例。
  • 示例:

package top.open1024.io.demo20;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 19:02
 */
public class Test {
    public static void main(String[] args) {
        try (PrintStream ps = new PrintStream(new FileOutputStream("d:/demo.txt"),true)) {
            ps.println(1);
            ps.println("2");
            ps.println('A');
            ps.println(100L);
            ps.println(true);
            ps.println("你好啊");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2.10 序列化

2.10.1 概述

  • Java提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的类型对象中存储的属性等信息。

  • 字节序列写出到文件之后,相当于文件中持久保存了一个对象信息;反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化

  • 对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。

img

2.10.2 ObjectOutputStream

  • java.io.ObjectOutputStream类是将Java对象的原始数据类型写出到文件以实现对象的持久存储。

  • 构造方法:

public ObjectOutputStream(OutputStream out) throws IOException {}
  • 序列化操作:

    • ① 类必须实现java.io.Serializable接口,Serializable是一个标记接口,不实现此接口的类不会使任何状态序列化或反序列化,会抛出NotSerializableException异常(如果类中的某个属性也是引用数据类型,那么该属性如果也要序列化,必须实现Serializable接口)。
    • ② 该类的所有属性必须是可序列化的。如果有一个属性不需要序列化的,则该属性必须注明是瞬时态的,使用transient关键字修饰。
    • ③ 静态变量的值不会序列化。
  • 写出对象的方法:

public final void writeObject(Object obj) throws IOException {}
  • 示例:
package top.open1024.io.demo21;

import java.io.Serializable;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 21:48
 */
public class Person implements Serializable {

    private String name;

    private Integer age;

    public Person() {}

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

    public String getName() {
        return this.name;
    }

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

    public Integer getAge() {
        return this.age;
    }

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

    @Override
    public String toString() {
        return "Person{" + "name='" + this.name + '\'' + ", age=" + this.age + '}';
    }
}
package top.open1024.io.demo21;

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

/**
 * 序列化
 * 
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 21:14
 */
public class Test {
    public static void main(String[] args) {
        Person person = new Person("张三", 12);
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"))) {
            oos.writeObject(person);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

2.10.3 ObjectInputStream

  • java.io.ObjectInputStream类是将之前使用ObjectOutputStream序列化的原始数据恢复成对象。

  • 构造方法:

public ObjectInputStream(InputStream in) throws IOException {}
  • 读取对象的方法:
public final Object readObject()
    throws IOException, ClassNotFoundException {}
  • 示例:
package top.open1024.io.demo21;

import java.io.Serializable;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 21:48
 */
public class Person implements Serializable {

    private String name;

    private Integer age;

    public Person() {}

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

    public String getName() {
        return this.name;
    }

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

    public Integer getAge() {
        return this.age;
    }

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

    @Override
    public String toString() {
        return "Person{" + "name='" + this.name + '\'' + ", age=" + this.age + '}';
    }
}
package top.open1024.io.demo21;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

/**
 * 反序列化
 * 
 * @author open1024
 * @version 1.0
 * @since 2021-10-05 22:12
 */
public class Test2 {
    public static void main(String[] args) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) {
            Person person = (Person)ois.readObject();
            System.out.println("person = " + person);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
0

评论区