Java IO:文件读写、流操作与常用技巧

IO流

概述

Java IO流指的是Java输入输出流,用于处理与文件、网络等设备之间的数据传输。Java提供了InputStreamOutputStream两个抽象类作为所有输入输出流类的基类,以及ReaderWriter两个抽象类作为所有字符输入输出流类的基类。同时,Java还提供了许多具体的输入输出流类和字符输入输出流类,如FileInputStream、FileOutputStream、BufferedInputStream、BufferedOutputStream、InputStreamReader、OutputStreamWriter等。这些类可用于读取文件、写入数据到文件、从网络中读取数据、向网络中写入数据等常见操作。

输出流:程序 -> 文件

输入流:文件 -> 程序

作用

Java IO流主要用于处理与文件、网络等设备之间的数据传输。其具体作用包括:

  1. 从文件中读取数据或将数据写入到文件中
  2. 从网络中读取数据或将数据写入到网络中
  3. 处理字节数据或字符数据
  4. 支持字符串、基本类型、对象等不同类型数据的读取和写入
  5. 支持对数据进行缓存,以提高读写性能
  6. 实现对文件、目录操作,如创建、删除等
  7. 实现序列化和反序列化,使得对象可以在不同系统之间传输和存储
  8. 支持压缩和解压缩文件,减小文件大小。

Java IO流为Java程序处理输入输出提供了丰富而灵活的方式,适用于各种场景和应用。

分类

Java IO流可以分为四种类型:字节输入输出流、字符输入输出流、字节缓冲输入输出流和字符缓冲输入输出流

  1. 字节输入输出流(InputStream和OutputStream):用于处理读写字节数据,如二进制文件、图片、音频等。
  2. 字符输入输出流(Reader和Writer):用于处理读写字符数据,如文本文件、网页等。
  3. 字节缓冲输入输出流(BufferedInputStream和BufferedOutputStream):通过缓存方式提高了字节输入输出流的性能,适用于处理大量的字节数据。
  4. 字符缓冲输入输出流(BufferedReader和BufferedWriter):通过缓存方式提高了字符输入输出流的性能,适用于处理大量的字符数据。

此外,Java IO流还可以根据不同的来源和目的地进行分类,如:

  1. 文件输入输出流(FileInputStream和FileOutputStream):用于读写文件。
  2. 管道输入输出流(PipedInputStream和PipedOutputStream):用于线程间的数据传输。
  3. 套接字输入输出流(SocketInputStream和SocketOutputStream):用于与其他计算机上的程序进行通信。
  4. 标准输入输出流(System.in和System.out):用于控制台输入输出。

IO流的体系

字节流

字节输入流(InputStream)

FileInputStream

使用字节输入流可以读取本地文件中的数据加载到程序中进行操作

方法说明
public int read()一次读一个字节数据
public int read(byte[] buffer)一次读一个字节数组数据
//创建对象
FileInputStream fis = new FileInputStream("文件所在路径");
//public int read(),循环读取数据
int b;
while ((b = fis.read()) != -1) {
    System.out.print(((char) b));
}
//释放资源
fis.close();

创建字节输入流细节

如果文件不存在,使用字节输入流会抛出异常并报错

读取数据细节

  1. 使用字节输入流每次可以读取一个字节,并将该字节转换为其对应的ASCII码值
  2. 当使用字节输入流读取文件时,当读取到文件末尾时read()方法将返回-1

释放资源细节

为了避免持续占用资源,每次使用输入流或输出流后都应该释放其对应的资源。

字节输出流(OutputStream)

FileOutputStream

使用字节输出流可以将程序中的数据写入到本地文件中

//创建对象
FileOutputStream fos = new FileOutputStream("文件所在路径");
//or
FileOutputStream fos = new FileOutputStream(new File("文件所在路径"));
//or,续写开关,默认为false
FileOutputStream fos = new FileOutputStream("文件所在路径", true);
//写出数据
fos.write(99);
//void write(byte[] b)
fos.write(new byte[]{111, 121, 100, 101, 115});
void write(byte[] b, int off, int len)
fos.write(bytes, 1, 3); //从下标为1开始写入,写入3个
//换行写,使用/r/n
fos.write("rqz\r\n779".getBytes());
//释放数据
fos.close();

创建字节输出流对象细节

  1. 参数是字符串表示的路径或者是File对象
  2. 如果文件不存在会创建一个的文件,但是要保证父级路径是存在的。
  3. 如果文件已经存在,则会清空文件。

写入数据细节

字节输出流中的write()方法参数为整数,但实际上在文件中写入的是该整数所对应的ASCII字符

释放资源细节

为了避免持续占用资源,每次使用输入流或输出流后都应该释放其对应的资源。

换行细节

在Windows操作系统中,Java对回车换行进行了优化。尽管完整的换行符为\r\n,但只需使用其中一个\r或\n也可以实现换行,因为Java会在底层自动补全缺少的字符。

文件拷贝功能

为了避免覆盖先前读取操作的内容,重要的是指定从输入流中读取的字节数长度。如果未指定长度,则可能在字节数组中存在来自上一次读取操作的残留内容,如果字节数组没有被最近的读取操作完全填满,则在下一个写入操作期间会导致意外数据被写入。

// 1. 创建一个字节数组作为缓冲区
byte[] buffer = new byte[1024];
// 2. 创建一个 FileInputStream 对象用于读取文件
FileInputStream fis = new FileInputStream("input.txt");
// 3. 创建一个 FileOutputStream 对象用于写入文件
FileOutputStream fos = new FileOutputStream("output.txt");
// 4. 循环读取文件内容到缓冲区,并将缓冲区中的数据写入到输出文件中
int length;
while ((length = fis.read(buffer)) != -1) {
    fos.write(buffer, 0, length);
}
// 5. 关闭输入输出流
fis.close();
fos.close();

该代码通过创建一个字节数组作为缓冲区来提高读写效率,先通过FileInputStream对象读取input.txt文件内容到缓冲区中,再通过FileOutputStream对象将缓冲区中的数据写入到output.txt文件中。最后关闭输入输出流并输出复制成功消息。

字符流

字符输入流(Reader)

  • 字符输入流(Reader)是Java IO流体系中的一个抽象类,用于读取字符数据。它是所有字符输入流类的基类,提供了一些常用的读取字符的方法,如read()readLine()等。

  • 与字节输入流不同,字符输入流处理的是字符数据,以字符形式进行读写操作。InputStream对象每次读取一个字节,而Reader对象则每次读取一个字符,因此如果需要处理文本文件或其他字符数据,应该使用字符输入流来读取数据

  • Java IO流中还提供了许多具体的字符输入流类,如FileReader、InputStreamReader、BufferedReader等,这些类可以根据不同的需求和场景提供更加丰富和灵活的字符输入流读取方式。

FileReader
方法说明
public int read()读取数据,读到末尾返回-1
public int read(char[] cbuf)读取多个数据,读到末尾返回-1
//public int read()
//1.创建对象并关联本地文件
FileReader frd = new FileReader("文件所在路径");
//2.读取数据 read()
int ch;
while ((ch = frd.read()) != -1) {
    //默认显示的是十进制数据,查看中文需要进行char强转
    System.out.print((char)ch);
}
//3.释放资源
frd.close();

//public int read(char[] cbuf)
//1.创建对象并关联本地文件
FileReader frd = new FileReader("文件所在路径");
//2.读取数据 read(char[] cbuf)
char[] chars = new char[1024 * 1024 * 5];
int len;
while ((len = frd.read(chars)) != -1) {
    //把数组中的数据变成字符串再进行打印
    System.out.print(new String(chars, 0, len));
}
//3.释放资源
frd.close();

read()细节

  1. 字符流的底层也是字节流,默认是一个字节一个字节的读取,当字符流遇到中文字符时,会读取多个字节。这是因为中文字符在计算机内部以多个字节的形式表示。
  2. 在读取之后,方法底层还是会进行解码并转成十进制

read(char[] cbuf)细节

此方法是将数据读取、解码和强转三个步骤合并,并在完成强转后才将字符放入数组中。

原理解析
  1. 创建字符输入流对象
    • 底层会关联文件,并创建缓冲区(长度8192的字节数组)
  2. 读取数据
    • 底层会优先检查缓冲区是否有可读数据,若没有,则会从文件中读取数据并填充到缓冲区中,每次尽可能填满缓冲区。如果文件中也没有数据可读,则返回-1。如果缓冲区内有数据可读,则直接从缓冲区读取,而不需要再去文件中获取数据。

字符输出流(Writer)

  • 字符输出流(Writer)是Java IO流体系中的一个抽象类,用于写入字符数据。它是所有字符输出流类的基类,提供了一些常用的写入字符的方法,如write()flush()等。

  • 与字节输出流不同,字符输出流处理的是字符数据,以字符形式进行读写操作。OutputStream对象每次写入一个字节,而Writer对象则每次写入一个字符,因此如果需要处理文本文件或其他字符数据,应该使用字符输出流来写入数据

  • Java IO流中还提供了许多具体的字符输出流类,如FileWriter、OutputStreamWriter、BufferedWriter等,这些类可以根据不同的需求和场景提供更加丰富和灵活的字符输出流写入方式。

FileWiter
方法说明
void write(int c)写出一个字符
void write(String str)写出一个字符串
void write(String str, int off, int len)写出一个字符串一部分
void write(char[] cbuf)写出一个字符数组
void write(char[] cbuf, int off, int len)写出字符数组一部分
public void flush()将缓冲区的数据,刷新到本地文件中
public void close()释放资源/关流
//1.创建对象并关联本地文件
FileWriter fwt = new FileWriter("文件所在路径");
//2.写入数据 read(String str)
fwt.write("多学点");
//3.释放资源
fwt.close();
原理解析
  1. 创建字符输出流对象:首先需要创建一个字符输出流对象,该对象通常与一个底层的输出设备或文件相关联。
  2. 写入数据到缓冲区:当开始使用字符输出流写入数据时,数据通常被先写入到一个内部的缓冲区中。这样做可以提高写入性能,因为每次写操作都会导致底层设备或文件的IO操作。
  3. 刷新缓冲区:当缓冲区满了或者需要强制将缓冲区的所有内容写入到底层设备或文件时,需要调用flush()方法刷新缓冲区。此时,内存缓冲区中的所有数据都将被写入到目标设备或文件中。
  4. 关闭流:最后,当不再需要写入数据时,需要关闭字符输出流。这个操作将清空缓冲区并释放任何系统资源。

总之,字符输出流工作原理的核心是采用缓冲区技术来提高写入性能,并允许操作者控制何时将数据写入物理设备。

编码与解码

编码的方法

方法说明
public byte[] getBytes()使用默认方式进行编码
public byte[] getBytes(String charsetName)使用指定方式进行编码
//1.默认编码
String str = "rqz搞快点";
byte[] bytes = str.getBytes();
//2.指定编码
String str = "rqz搞快点";
byte[] bytes = str.getBytes("GBK");

解码的方法

方法说明
String(byte[] bytes)使用默认方式进行解码
String(byte[] bytes, String charsetName)使用指定方式进行解码
//1.默认解码
String str = "rqz搞快点";
byte[] bytes = str.getBytes("GBK");
//idea默认使用utf-8进行解码
String s = new String(bytes);
System.out.println(s); //rqz����
//2.指定解码
String str = "rqz搞快点";
byte[] bytes = str.getBytes("GBK");
String s = new String(bytes, "GBK");
System.out.println(s); //rqz搞快点

案例

拷贝文件夹

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Objects;

public class FolderCopyExample {
    public static void main(String[] args) {
        String sourceFolderPath = "C:\\Users\\Rr\\Desktop\\1";
        String targetFolderPath = "C:\\Users\\Rr\\Desktop\\2";
        try {
            // 创建目标文件夹
            new File(targetFolderPath).mkdirs();
            // 获取源文件夹对象
            File sourceFolder = new File(sourceFolderPath);
            // 遍历源文件夹内的所有文件和子文件夹并递归复制它们
            copyFolder(sourceFolder, new File(targetFolderPath));
            System.out.println("Folder copied successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 递归复制文件夹及其内容
     */
    private static void copyFolder(File sourceFolder, File destinationFolder) throws IOException {
        // 如果源文件夹不存在,则直接退出方法
        if (!sourceFolder.exists()) {
            return;
        }
        // 如果目标文件夹不存在,则创建它
        if (!destinationFolder.exists()) {
            destinationFolder.mkdirs();
        }
        // 遍历源文件夹中所有的文件和子文件夹
        for (File file : Objects.requireNonNull(sourceFolder.listFiles())) {
            if (file.isDirectory()) {
                // 如果当前文件是一个文件夹,则递归调用copyFolder方法以复制该文件夹及其内容
                copyFolder(file, new File(destinationFolder, file.getName()));
            } else {
                // 如果当前文件不是一个文件夹,则使用Files.copy方法将文件复制到目标文件夹中
                Files.copy(file.toPath(), destinationFolder.toPath().resolve(file.getName()));
            }
        }
    }
}

文件加密

//创建文件对象
FileInputStream fis = new FileInputStream("文件所在路径");
FileOutputStream fos = new FileOutputStream("文件所在路径");
int b;
//读取文件
while ((b = fis.read()) != -1) {
    //通过异或操作写入文件
    fos.write(b ^ 779);
}
//释放资源
fos.close();
fis.close();

缓冲流

字节缓冲流

  • 字节缓冲流是Java中用于处理字节数据的一种输入输出流,它可以提供高效的读写操作。字节缓冲流内部维护了一个缓冲区,读写时先将数据存入缓冲区中,当缓冲区满时再将数据一次性写入或者读取出来,这样可以减少实际的I/O操作次数,提高读写操作的效率。Java中的字节缓冲流有两种类型:BufferedInputStreamBufferedOutputStream

  • 其中BufferedInputStream可以从另一个输入流中读取数据,并将其存储在内部缓冲区中,而BufferedOutputStream则可以将数据写入另一个输出流中,并将其存储在内部缓冲区中,直到缓冲区被填满或者调用了flush()方法才会将数据真正写入输出流中。

底层自带了长度为8192的字节数组缓冲区提高性能

BufferedInputStream

方法说明
public BufferedInputStream (InputStream is)把基本流包装成高级流,提高读取数据的性能

BufferedOutputStream

方法说明
public BufferedInputStream (OutputStream os)把基本流包装成高级流,提高写出数据的性能

利用字节缓冲流拷贝文件

//源文件路径
String sourceFile = "源文件路径";
//目标文件路径
String destinationFile = "目标文件路径";
//创建输入输出缓冲流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destinationFile));
//循环读取并写到目标文件
byte[] bytes = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(bytes)) != -1) {
    bos.write(bytes,0,bytesRead);
}
//释放资源
bos.close();
bis.close();

字符缓冲流

字符缓冲流是Java I/O中的一种流,用于处理字符数据。它继承自Reader和Writer类,可以以缓冲方式读写字符数据,提高输入输出的效率。

与普通的Reader和Writer相比,字符缓冲流具有以下特点:

  1. 使用内部缓冲区,可以减少IO操作的次数,提高输入输出效率。
  2. 可以指定缓冲区大小,以适应不同的应用场景。
  3. 读取和写入的字符数据是以行为单位进行的,方便对文本文件进行处理。
  4. 支持mark和reset操作,方便在读取和写入过程中回到之前的位置。
  5. 可以与其他字符流和字节流组合使用,方便进行转换和处理。

常用的字符缓冲流有BufferedReaderBufferedWriter。其中,BufferedReader主要用于从字符输入流中读取文本数据,而BufferedWriter则用于向字符输出流中写入文本数据

底层自带了长度为8192的字符数组缓冲区提高性能,一个字符为2个字节

BufferedReader

方法说明
public BufferedReader (Reader r)把基本流包装成高级流
public String readLine()读取一行数据,如果没有数据可读了,会返回null
//获取基本流对象
FileReader fileReader = new FileReader("example.txt");
//把基本流包装成高级流
BufferedReader bufferedReader = new BufferedReader(fileReader);
//接收每一行数据
String line;
//循环读取每一行数据,如果没有数据可读了,会返回null
while ((line = bufferedReader.readLine()) != null) {
    System.out.println(line);
}
//释放资源
bufferedReader.close();

BufferedWriter

方法说明
public BufferedWriter (Reader r)把基本流包装成高级流
public String newLine()跨平台的换行
//获取基本流对象
FileWriter fileWriter = new FileWriter("example.txt");
//把基本流包装成高级流
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
//字符串文本
String text = "Hello, world!\nThis is an example.\n";
//写入数据
bufferedWriter.write(text);
//换行(可跨平台)
bufferedWriter.newLine();
//释放资源
bufferedWriter.close();

转换流

  • Java转换流是Java I/O库中的一种流,在字节流和字符流之间进行转换。它主要用于处理字符数据与字节数据之间的转换,是Reader和Writer类的一种包装。转换流可以将字节流转换为字符流,也可以将字符流转换为字节流。

  • 转换流有两种类型:InputStreamReaderOutputStreamWriter。其中,InputStreamReader用于将字节输入流转换为字符输入流,而OutputStreamWriter则用于将字符输出流转换为字节输出流。转换时,需要指定字符编码,例如UTF-8或GBK等。

  • 使用转换流的主要优点是可以同时处理字节流和字符流,并且可以在不同编码方式之间转换数据,方便进行跨平台开发和国际化处理。常见的应用场景包括读取和写入文本文件、处理网络数据和操作数据库等。

读取数据

FileReader为JDK11后的InputStreamReader替代方案

//创建转换流对象并指定字符集编码
FileReader fr = new FileReader("文件所在路径", Charset.forName("GBK"));
//读取数据
int data;
while ((data = fr.read()) != -1) {
    System.out.print((char) data);
}
//释放资源
fr.close();

写入数据

FileWriter fw = new FileWriter("文件所在路径", Charset.forName("GBK"));
fw.write("rqz多学点");
fw.close();

案例

//利用字作流读取文件中的数据,每次读一整行,而且不能出现乱码

//获取字节文件对象
FileInputStream fis = new FileInputStream("example.txt");
//通过转换流将字节文件对象转换为字符文件对象,并指定字符编码
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
//创建字符缓冲流
BufferedReader br = new BufferedReader(isr);
//循环读取数据
String line;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}
//释放资源
br.close();

序列化流

  • Java序列化流是Java I/O库中的一种流,用于将对象转换为字节流以便进行存储或传输。序列化流可以将一个包含数据的对象转换为二进制格式的字节数组,方便在网络上进行传输或者在文件中进行存储。

  • 使用序列化流的主要优点是方便实现对象的持久化,即在程序结束后仍然能够保留对象状态和数据。同时,序列化流还可以用于实现远程方法调用(RMI)和分布式应用程序等。

  • Java提供了两个主要的序列化流:ObjectInputStreamObjectOutputStream。其中,ObjectOutputStream用于将对象写入输出流中,而ObjectInputStream则用于从输入流中读取对象。在使用这些流时,需要注意对象必须实现Serializable接口,否则会抛出NotSerializableException异常。

import java.io.*;

public class SerializableExample {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 将对象写入文件,
        FileOutputStream fos = new FileOutputStream("文件所在路径");
        //创建序列化流对象/对象操作输出流
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //创建对象
        Person person = new Person("Tom", 20);
        //写出数据
        oos.writeObject(person);
        //释放资源
        oos.close();

        // 从文件中读取对象
        FileInputStream fis = new FileInputStream("文件所在路径");
        //创建反序列化流对象/对象操作输入流
        ObjectInputStream ois = new ObjectInputStream(fis);
        Person newPerson = (Person) ois.readObject();
        System.out.println(newPerson);
        ois.close();
    }
}

// 实现Serializable接口的类
class Person implements Serializable {
    //为了确保反序列化时能够正确地载入对象,建议显示声明serialVersionUID。
    private static final long serialVersionUID = 1L;
    private String name;
    //transient瞬态关键字,不会把当前属性序列化到本地文件中
    private transient int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

细节

  1. 使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口。否则,会出现NotSerializableException异常。
  2. 序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了。
  3. 序列化对象后,修改了Javabean类,再次反序列化,会抛出InvalidClassException异常。解决方案:给JavaBean类添加serialVersionUID(序列号、版本号)。
  4. 一个对象中的某个成员变量的值不想被序列化解决方案:给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程。

读写多个对象

import java.io.*;
import java.util.ArrayList;

public class SerializableExample {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 将多个对象写入文件
        FileOutputStream fos = new FileOutputStream("example.ser");
        //创建序列化流对象/对象操作输出流
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //创建ArrayList对象,将所有对象放在ArrayList内
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("Tom", 20));
        personList.add(new Person("Jerry", 22));
        personList.add(new Person("Alice", 18));
        //写出ArrayList
        oos.writeObject(personList);
        //释放资源
        oos.close();
        // 从文件中读取多个对象
        FileInputStream fis = new FileInputStream("example.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ArrayList<Person> newPersonList = (ArrayList<Person>) ois.readObject();
        for (Person person : newPersonList) {
            System.out.println(person);
        }
        ois.close();
    }
}

// 实现Serializable接口的类
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

打印流

字节打印流

  • Java字节打印流是Java I/O库中的一种流,它可以将数据转换为字节,并输出到指定输出流中。字节打印流主要用于向文件或网络等数据通道写入文本或二进制数据。

  • Java提供了两种主要的字节打印流:PrintStreamPrintWriter。其中,PrintStream处理字节流的打印流,而PrintWriter则是处理字符流的打印流

  • 使用字节打印流的主要优点是简化了输出操作,可以直接输出各种类型的数据,包括字符串、整数、浮点数等,同时可以自动进行格式化。另外,字节打印流还提供了一些特殊功能,例如自动刷新、自定义分隔符等。

  • 需要注意的是,在使用字节打印流时,必须显式指定输出流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭打印流。

字节流底层没有缓冲区,开不开自动刷新都一样

//创建字节打印流,并指定字符集
PrintStream ps = new PrintStream("文件所在路径", "GBk");
//写入字符串,并换行
ps.println("Hello World!");
//写入字符串,格式化输出
ps.printf("My name is %s, I'm %d years old.", "Tom", 20);
//释放资源
ps.close();

字符打印流

  • Java字符打印流是Java I/O库中的一种流,它可以将数据转换为字符,并输出到指定输出流中。字符打印流主要用于向文件或网络等数据通道写入文本或字符数据。

  • Java提供了两种主要的字符打印流:PrintWriterPrintStream。其中,PrintWriter处理字符流的打印流,而PrintStream则是处理字节流的打印流

  • 使用字符打印流的主要优点是简化了输出操作,可以直接输出各种类型的数据,包括字符串、整数、浮点数等,同时可以自动进行格式化。另外,字符打印流还提供了一些特殊功能,例如自动刷新、自定义分隔符等。

  • 需要注意的是,在使用字符打印流时,必须显式指定输出流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭打印流。

字符流底层有缓冲区,想要自动刷新需要开启

//创建文件对象
FileWriter fw = new FileWriter("example.txt");
//创建字符打印流对象,开启自动刷新
PrintWriter pw = new PrintWriter(fw, true);
//写入字符串,并换行
pw.println("Hello World!");
//写入字符串,格式化输出
pw.printf("My name is %s, I'm %d years old.", "Tom", 20);
//释放资源
pw.close();

压缩流

解压缩流

  • Java解压缩流是Java I/O库中的一种流,用于解压已经压缩过的数据。可以使用解压缩流来读取压缩文件,并将其中的数据解压缩后输出到目标数据通道中。

  • Java提供了两种主要的解压缩流:InflaterInputStreamGZIPInputStream。其中,InflaterInputStream是通用的解压缩流,可以处理各种常见的压缩格式,例如Zip、Gzip、Deflate等;而GZIPInputStream专门用于处理Gzip压缩格式

  • 使用解压缩流的主要优点是简化了解压缩操作,可以直接从压缩文件中读取数据,同时可以自动进行解压缩。另外,解压缩流还提供了一些特殊功能,例如自动跳过头部信息、自定义缓冲区大小等。

  • 需要注意的是,在使用解压缩流时,必须显式指定输入流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭流。

压缩流

  • Java压缩流是Java I/O库中的一种流,用于将数据压缩为指定格式并输出到目标数据通道中。可以使用压缩流来创建压缩文件,并将其中的数据压缩后输出到目标数据通道中。
  • Java提供了两种主要的压缩流:DeflaterOutputStreamGZIPOutputStream。其中,DeflaterOutputStream是通用的压缩流,可以处理各种常见的压缩格式,例如Zip、Gzip、Deflate等;而GZIPOutputStream专门用于处理Gzip压缩格式
  • 使用压缩流的主要优点是简化了压缩操作,可以直接将数据写入压缩文件中,同时可以自动进行压缩。另外,压缩流还提供了一些特殊功能,例如自定义缓冲区大小、设置压缩级别等。
  • 需要注意的是,在使用压缩流时,必须显式指定输出流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭流。

工具包

Commons-io

Commons-io是一个开源的Java库,提供了一系列实用类和方法,用于处理常见的输入输出(I/O)操作。这个库可以大大简化I/O编程任务,例如读写文件、拷贝文件、处理字节和字符流等。Commons-io还提供了许多方便的工具方法,例如比较文件内容、查找文件、解析URL等。它是Apache Commons项目的一部分,可以被广泛应用于Java开发中。

Commons-io提供了众多实用方法,下面列举其中一些常用的方法:

  1. FileUtils类:提供了许多操作文件的方法,如读写文件、拷贝文件、删除文件等。
  2. IOUtils类:提供了处理输入输出流的方法,如复制输入流到输出流、关闭流等。
  3. FilenameUtils类:提供了处理文件名和路径的方法,如获取文件扩展名、合并路径、规范化路径等。
  4. FileSystemUtils类:提供了操作文件系统的方法,如获取磁盘空间大小、检查是否支持符号链接等。
  5. DigestUtils类:提供了生成消息摘要的方法,如MD5、SHA等。

这些方法都提供了高度的可定制性和灵活性,可以满足不同场景的需求。

Hutool

Hutool是一个开源的Java工具库,提供了丰富的工具类和方法,包括字符串处理、日期时间处理、文件操作、加密解密、网络请求、XML/JSON解析等常见功能。Hutool致力于简化Java开发过程中的常用操作,提高开发效率。它的设计理念是易用、可靠、高效,并且提供了简洁易懂的API文档和示例代码,方便开发者上手使用。Hutool也是国内比较受欢迎的Java工具库之一。

Hutool提供了众多实用方法,下面列举其中一些常用的方法:

  1. StrUtil类:提供了许多字符串处理方法,如判空、拼接、格式化等。
  2. DateUtil类:提供了日期时间处理方法,如格式化、计算、转换等。
  3. FileUtil类:提供了文件操作方法,如读写文件、复制文件、删除文件等。
  4. EncryptUtil类:提供了加密解密方法,如MD5、SHA、AES等。
  5. HttpUtil类:提供了网络请求方法,如Get、Post、上传下载文件等。
  6. JSONUtil类:提供了JSON解析方法,如对象序列化、JSON字符串转对象等。

这些方法都提供了高度的可定制性和灵活性,可以满足不同场景的需求。Hutool还提供了其他许多实用的工具类和方法,包括集合操作、XML解析、正则表达式等,可以大大简化Java开发过程中的编码工作。

  • 38
    点赞
  • 133
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java IO学习总结 Java操作有关的类或接口: Java类图结构: 的概念和作用 是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为的本质是数据传输,根据数据传输特性将抽象为各种类,方便更直观的进行数据操作IO的分类 根据处理数据类型的不同分为:字符和字节 根据数据向不同分为:输入和输出 字符和字节 字符的由来: 因为数据编码的不同,而有了对字符进行高效操作对象。本质其实就是基于字节读取时,去查了指定的码表。 字节和字符的区别: 读写单位不同:字节以字节(8bit)为单位,字符以字符为单位,根据码表映射字符,一次可能读多个字节。 处理对象不同:字节能处理所有类型的数据(如图片、avi等),而字符只能处理字符类型的数据。 结论:只要是处理纯文本数据,就优先考虑使用字符。 除此之外都使用字节输入和输出输入只能进行读操作,对输出只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的Java IO对象 1.输入字节InputStreamIO输入字节的继承图可见上图,可以看出: InputStream 是所有的输入字节的父类,它是一个抽象类。 ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。 ObjectInputStream 和所有FilterInputStream 的子类都是装饰(装饰器模式的主角)。 2.输出字节OutputStream IO 中输出字节的继承图可见上图,可以看出: OutputStream 是所有的输出字节的父类,它是一个抽象类。 ByteArrayOutputStream、FileOutputStream 是两种基本的介质,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据, ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰。 3.字节输入与输出的对应 图中蓝色的为主要的对应部分,红色的部分就是不对应部分。紫色的虚线部分代表这些一般要搭配使用。从上面的图中可以看出Java IO 中的字节是极其对称的。“存在及合理”我们看看这些字节中不太对称的几个类吧! LineNumberInputStream 主要完成从读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入了。 PushbackInputStream 的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。 StringBufferInputStream 已经被Deprecated,本身就不应该出现在InputStream 部分,主要因为String 应该属于字符的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。 SequenceInputStream 可以认为是一个工具类,将两个或者多个输入当成一个输入依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构,却让其更“纯洁”――纯洁的Decorator 模式。 PrintStream 也可以认为是一个辅助工具。主要可以向其他输出,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例! 4.字符输入Reader 在上面的继承关系图中可以看出: Reader 是所有的输入字符的父类,它是一个抽象类。 CharReader、StringReader 是两种基本的介质,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。 BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。 FilterReader 是所有自定义具体装饰的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。 InputStreamReader 是一个连接字节和字符的桥梁,它将字节转变为字符。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。 5.字符输出Writer 在上面的关系图中可以看出: Writer 是所有的输出字符的父类,它是一个抽象类。 CharArrayWriter、StringWriter 是两种基本的介质,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据, BufferedWriter 是一个装饰器为Writer 提供缓冲功能。 PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。 OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。 6.字符输入与输出的对应 7.字符与字节转换 转换的特点: 其是字符和字节之间的桥梁 可对读取到的字节数据经过指定编码转换成字符 可对读取到的字符数据经过指定编码转换成字节 何时使用转换? 当字节和字符之间有转换动作时; 操作的数据需要编码或解码时。 具体的对象体现: InputStreamReader:字节到字符的桥梁 OutputStreamWriter:字符到字节的桥梁 这两个对象是字符体系中的成员,它们有转换作用,本身又是字符,所以在构造的时候需要传入字节对象进来。 8.File类 File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 9.RandomAccessFile类 该对象并不是体系中的一员,其封装了字节,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点: 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw) 注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值