Java IO处理

1、IO

1、File类

被定义为文件和目录路径名的抽象表现形式,这是因为File类既可以表示文件也可以表示目录,他们都通过对应的路径来描述。

创建一个File类:
File f = new File("D:\\temp.txt"); //通过f对temp.txt进行操作

File类的常用方法

构造方法
  • File(String pathname)
    通过路径字符串创建对象
  • File(String parent, String child)
    通过父路径和子路径组合创建对象
  • File(File parent, String child)
    通过父File对象和子路径组合创建对象
文件检测
  • boolean exists()
    检测文件/目录是否存在
  • boolean isFile()
    判断是否是文件
  • boolean isDirectory()
    判断是否是目录
  • boolean canRead()
    检测是否可读
  • boolean canWrite()
    检测是否可写
文件操作
  • boolean createNewFile()
    创建新文件(仅当文件不存在时)
  • boolean delete()
    删除文件或空目录
  • boolean renameTo(File dest)
    重命名/移动文件
路径获取
  • String getPath()
    获取相对路径字符串
  • String getAbsolutePath()
    获取绝对路径字符串
  • String getName()
    获取文件名/目录名
  • long length()
    获取文件字节数
目录操作
  • boolean mkdir()
    创建单级目录
  • boolean mkdirs()
    创建多级目录
  • String[] list()
    获取目录下的文件名数组
  • File[] listFiles()
    获取目录下的File对象数组
其他方法
  • long lastModified()
    获取最后修改时间戳
  • boolean setReadOnly()
    设置为只读
  • File[] listRoots()
    获取系统根目录(如Windows的盘符)

2、IO流概述

1、什么是IO流

I/OInput/Output 的缩写,I/O 技术是非常实用的技术,用于处理设备之间的数据传输。如读 / 写文件,网络通讯等。
IO 流是一组有序的,有起点和终点的数据集合,是对数据传输的总称和抽象。

IO 作用:

  • 人机交互
  • 文件数据读取写入,数据持久化保存

IO 流的源和目的地:

  • 内存
  • 控制台
  • 磁盘文件
  • 网络端点

关于 InputOutput

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

2、IO流分类

根据处理的数据单元不同:

  • 字节流:操作的数据单元是8位字节InputStreamOutputStream。二进制文件(声音、图片、视频)、文本文件;
  • 字符流:操作的数据单元是16位字符ReaderWriter,通常处理文本文件。

根据数据流向不同:

  • 输入流:硬盘->内存,只能从中读取数据,而不能向其写入数据。 InputStreamReader
  • 输出流:内存->硬盘,只能向其写入数据,而不能从中读取数据。OutputStreamWriter

IO流大概有40多个子类,因这四个流都是抽象类,因此子类才是平常调用的类。

3、IO流处理流程

  1. 打开流
  2. 在流中进行相应的操作(输入读取,输出写入)
  3. 关闭流(程序中打开的文件所产生的IO资源不属于内存里的资源,垃圾回收机制无法进行回收,因此需要显示的关闭文件IO资源)

3、字节流

1、InputStream

InputStream 是所有字节输入流的父类,用于从源中读取字节数据。常见的子类包括:

  • FileInputStream:从文件系统中的某个文件中获取输入字节。
    • 方法
      • int read():从输入流中读取一个字节的数据。
      • int read(byte[] b):从输入流中读取一定数量的字节,并将其存储到字节数组中。
      • int read(byte[] b, int off, int len):从输入流中读取一定数量的字节,并将其存储到字节数组的指定偏移量位置。
      • void close():关闭输入流并释放与之相关的系统资源。
  • ByteArrayInputStream:将字节数组作为输入流。
    • 方法
      • int read():从字节数组中读取一个字节。
      • int read(byte[] b):从字节数组中读取一定数量的字节。
      • void reset():将流的偏移量重置为0。
      • void mark(int readlimit):标记当前的读取位置。
  • BufferedInputStream:带有缓冲区的输入流,可以提高读取效率。
    • 方法
      • int read():从缓冲区中读取一个字节。
      • int read(byte[] b):从缓冲区中读取一定数量的字节。
      • void mark(int readlimit):标记当前的读取位置。
      • void reset():将流的偏移量重置到标记的位置。
  • DataInputStream:允许从输入流中读取基本Java数据类型的数据。
    • 方法
      • int readInt():从输入流中读取一个整数。
      • float readFloat():从输入流中读取一个浮点数。
      • double readDouble():从输入流中读取一个双精度浮点数。
      • String readUTF():从输入流中读取一个字符串。

2、OutputStream

OutputStream 是所有字节输出流的父类,用于向目标写入字节数据。常见的子类包括:

  • FileOutputStream:将字节写入文件系统中的某个文件。
    • 方法
      • void write(int b):将一个字节写入输出流。
      • void write(byte[] b):将字节数组中的所有字节写入输出流。
      • void write(byte[] b, int off, int len):将字节数组中的一部分字节写入输出流。
      • void close():关闭输出流并释放与之相关的系统资源。
  • ByteArrayOutputStream:将字节写入字节数组。
    • 方法
      • void write(int b):将一个字节写入字节数组。
      • void write(byte[] b):将字节数组中的所有字节写入字节数组。
      • byte[] toByteArray():将字节数组输出流的内容转换为字节数组。
      • void reset():清空字节数组输出流。
  • BufferedOutputStream:带有缓冲区的输出流,可以提高写入效率。
    • 方法
      • void write(int b):将一个字节写入缓冲区。
      • void write(byte[] b):将字节数组中的所有字节写入缓冲区。
      • void flush():清空缓冲区,将所有数据写入目标。
  • DataOutputStream:允许将基本Java数据类型的数据写入输出流。
    • 方法
      • void writeInt(int v):将一个整数写入输出流。
      • void writeFloat(float v):将一个浮点数写入输出流。
      • void writeDouble(double v):将一个双精度浮点数写入输出流。
      • void writeUTF(String str):将一个字符串写入输出流。

3、字节流实现文件拷贝

使用字节流实现文件拷贝的步骤如下:

  1. 创建源文件的 FileInputStream 对象。
  2. 创建目标文件的 FileOutputStream 对象。
  3. 使用 read() 方法从源文件读取字节数据,并使用 write() 方法将数据写入目标文件。
  4. 关闭输入流和输出流,释放资源。

4、字符流

1、Reader

Reader 是所有字符输入流的父类,用于从源中读取字符数据。常见的子类包括:

  • FileReader:从文件系统中的某个文件中获取字符输入。
    • 方法
      • int read():从输入流中读取一个字符。
      • int read(char[] cbuf):从输入流中读取一定数量的字符,并将其存储到字符数组中。
      • int read(char[] cbuf, int off, int len):从输入流中读取一定数量的字符,并将其存储到字符数组的指定偏移量位置。
      • void close():关闭输入流并释放与之相关的系统资源。
  • BufferedReader:带有缓冲区的字符输入流,可以提高读取效率。
    • 方法
      • int read():从缓冲区中读取一个字符。
      • int read(char[] cbuf):从缓冲区中读取一定数量的字符。
      • String readLine():从输入流中读取一行文本。
      • void mark(int readlimit):标记当前的读取位置。
      • void reset():将流的偏移量重置到标记的位置。
  • StringReader:将字符串作为字符输入流。
    • 方法
      • int read():从字符串中读取一个字符。
      • int read(char[] cbuf):从字符串中读取一定数量的字符。
      • void reset():将流的偏移量重置为0。

2、Writer

Writer 是所有字符输出流的父类,用于向目标写入字符数据。常见的子类包括:

  • FileWriter:将字符写入文件系统中的某个文件。
    • 方法
      • void write(int c):将一个字符写入输出流。
      • void write(char[] cbuf):将字符数组中的所有字符写入输出流。
      • void write(char[] cbuf, int off, int len):将字符数组中的一部分字符写入输出流。
      • void write(String str):将字符串写入输出流。
      • void close():关闭输出流并释放与之相关的系统资源。
  • BufferedWriter:带有缓冲区的字符输出流,可以提高写入效率。
    • 方法
      • void write(int c):将一个字符写入缓冲区。
      • void write(char[] cbuf):将字符数组中的所有字符写入缓冲区。
      • void newLine():写入一个行分隔符。
      • void flush():清空缓冲区,将所有数据写入目标。
  • StringWriter:将字符写入字符串。
    • 方法
      • void write(int c):将一个字符写入字符串。
      • void write(char[] cbuf):将字符数组中的所有字符写入字符串。
      • String toString():将字符串输出流的内容转换为字符串。

3、字符流实现文件拷贝

使用字符流实现文件拷贝的步骤如下:

  1. 创建源文件的 FileReader 对象。
  2. 创建目标文件的 FileWriter 对象。
  3. 使用 read() 方法从源文件读取字符数据,并使用 write() 方法将数据写入目标文件。
  4. 关闭输入流和输出流,释放资源。

5、缓冲流

为了提高数据读写的效率,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,默认使用8192个字节或字符的缓冲区。缓冲流要套接在相应的节点流之上。

根据数据操作单位可以把缓冲流分为:

  • BufferedInputStreamBufferedOutputStream
  • BufferedReaderBufferedWriter

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

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

关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流。如果是带缓冲区的流对象的 close() 方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出。

1、使用缓冲流实现文件拷贝

使用缓冲流(BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter)实现文件拷贝可以提高效率。步骤如下:

  1. 创建源文件的缓冲输入流(BufferedInputStreamBufferedReader)。
  2. 创建目标文件的缓冲输出流(BufferedOutputStreamBufferedWriter)。
  3. 使用 read() 方法从缓冲输入流读取数据,并使用 write() 方法将数据写入缓冲输出流。
  4. 调用 flush() 方法清空缓冲区,确保所有数据都被写入目标文件。
  5. 关闭缓冲输入流和缓冲输出流,释放资源。

2、按行读取

使用 BufferedReaderreadLine() 方法可以按行读取文本文件的内容:

  1. 创建文件的 FileReader 对象,并将其包装为 BufferedReader
  2. 使用 readLine() 方法逐行读取文件内容,直到返回 null(表示文件末尾)。
  3. 处理每一行的内容。
  4. 关闭 BufferedReader,释放资源。

6、序列化和反序列化

1、简介

序列化(Serialization)是指将对象的状态信息转换为可以存储或传输的形式的过程。反序列化(Deserialization)则是将序列化后的数据重新转换为对象的过程。序列化和反序列化在Java中主要用于对象的持久化存储、网络传输等场景。

2、序列化

序列化是指将对象的状态信息转换为字节序列的过程。在Java中,通过实现 java.io.Serializable 接口来使一个类的对象可以被序列化。

  • 实现步骤
    1. 让类实现 Serializable 接口。
    2. 定义一个唯一的序列化ID,serialVersionUID的静态常量。
    3. 使用 ObjectOutputStream 将对象写入到输出流中。
    4. 关闭输出流。
  • 重要方法
    • ObjectOutputStream.writeObject(Object obj):将对象序列化并写入到输出流中。
    • ObjectOutputStream.flush():刷新输出流,确保所有数据都被写入。
    • ObjectOutputStream.close():关闭输出流并释放资源。
  • 注意事项
    • Serializable 是一个标记接口,不包含任何方法。
    • 如果类中包含非序列化字段,可以使用 transient 关键字修饰。
    • 序列化时,对象的类必须在运行时类路径中存在。

3、反序列化

反序列化是指将字节序列重新转换为对象的过程。在Java中,通过 ObjectInputStream 来实现反序列化。

  • 实现步骤
    1. 创建一个 ObjectInputStream,并将其绑定到一个输入流(如文件输入流)。
    2. 使用 ObjectInputStream.readObject() 方法读取对象。
    3. 关闭输入流。
  • 重要方法
    • ObjectInputStream.readObject():从输入流中读取对象。
    • ObjectInputStream.close():关闭输入流并释放资源。
  • 注意事项
    • 反序列化时,对象的类必须在运行时类路径中存在。
    • 如果对象的类在序列化后发生了变化(如添加或删除字段),可能会导致反序列化失败。
    • 可以通过实现 readObject()writeObject() 方法来自定义序列化和反序列化过程。

4、transient关键字

1、基本概念

transient 是一个Java关键字,用于修饰类的成员变量。被 transient 修饰的成员变量不会被序列化。在序列化过程中,这些变量会被忽略,不会被写入到输出流中。

2、使用场景
  • 敏感信息:某些成员变量可能包含敏感信息(如密码、密钥等),这些信息不应该被序列化。
  • 性能优化:某些成员变量的值可以在反序列化时重新计算或获取,不需要通过序列化保存。
  • 避免序列化不必要的字段:某些字段可能与对象的状态无关,或者在序列化时不需要保存。
3、示例代码

以下是一个简单的示例,展示如何使用 transient 关键字:

import java.io.*;

class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String username;
    private transient String password; // 不会被序列化

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

public class SerializationExample {
    public static void main(String[] args) {
        User user = new User("Alice", "123456");

        // 序列化
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) {
            oos.writeObject(user);
            System.out.println("对象已序列化:" + user);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {
            User deserializedUser = (User) ois.readObject();
            System.out.println("对象已反序列化:" + deserializedUser);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

输出结果

对象已序列化:User{username='Alice', password='123456'}
对象已反序列化:User{username='Alice', password='null'}

说明

  • 在反序列化后,password 字段的值为 null,因为它是 transient 字段,没有被序列化。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值