NIO-FileChannel源码分析

本文详细分析了Java中FileChannel与RandomAccessFile的工作原理,尤其关注于FileChannelImpl的实现细节。通过源码解析,展示了如何通过RandomAccessFile进行高效的数据读写,并解释了其与DataInput和DataOutput接口的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本来是想学习Netty的,但是Netty是一个NIO框架,因此在学习netty之前,还是先梳理一下NIO的知识。通过剖析源码理解NIO的设计原理。

本系列文章针对的是JDK1.8.0.161的源码。

上一篇对SocketChannel的源码进行了分析,本篇继续对FileChannel的源码进行解析。

RandomAccessFile

我们可以通过使用RandomAccessFile读写数据。也可以通过FileInputStream读数据或通过FileOutputStream写数据。但实际这三个类内部实际是一样的,我们就以RandomAccessFile为例子说明FileChannelImpl的实现。

接口

RandomAccessFile实现了DataInputDataOutput两个接口,即数据输入和输出接口。

public class RandomAccessFile implements DataOutput, DataInput, Closeable {

}

DataInput定义了一些基本的读取方法

  • 读取指定长度的字节数据
  • 读取数据并转换为基元类型。
  • 读取一行数据。读取到\r会丢弃,读取到\n会丢弃并停止继续读取。
  • 用UTF-8编码读取一个string

public interface DataInput {
    void readFully(byte b[]) throws IOException;
    void readFully(byte b[], int off, int len) throws IOException;
    int skipBytes(int n) throws IOException;
    XXX readXXX() throws IOException;
    String readLine() throws IOException;
    String readUTF() throws IOException;
}

DataOutput定义了一些基本的写方法

  • 写入指定长度字节数据到文件。
  • 将基元类型写入文件。
  • 使用UTF-8编码写入一个string到文件。
public interface DataOutput {
    void write(int b) throws IOException;
    void write(byte b[]) throws IOException;
    void write(byte b[], int off, int len) throws IOException;
    void writeXXX(XXX v) throws IOException;
    void writeUTF(String s) throws IOException;
}

创建实例

在创建RandomAccessFile我们需要传入两个参数:第一个是文件路径,第二个是文件访问方式。

public RandomAccessFile(String name, String mode)
    throws FileNotFoundException
{
    this(name != null ? new File(name) : null, mode);
}

public RandomAccessFile(File file, String mode)
    throws FileNotFoundException
{
    //File用于检查文件路径是否有效
    String name = (file != null ? file.getPath() : null);
    int imode = -1;
    //判断文件访问方式
    if (mode.equals("r"))
        imode = O_RDONLY;
    else if (mode.startsWith("rw")) {
        imode = O_RDWR;
        rw = true;
        if (mode.length() > 2) {
            if (mode.equals("rws"))
                imode |= O_SYNC;
            else if (mode.equals("rwd"))
                imode |= O_DSYNC;
            else
                imode = -1;
        }
    }
    if (imode < 0)
        throw new IllegalArgumentException("Illegal mode \"" + mode + "\" must be one of \"r\", \"rw\", \"rws\", or \"rwd\"");
    //检查读写权限
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkRead(name);
        if (rw) {
            security.checkWrite(name);
        }
    }
    if (name == null) {
        throw new NullPointerException();
    }
    if (file.isInvalid()) {
        throw new FileNotFoundException("Invalid file path");
    }
    fd = new FileDescriptor();
    fd.attach(this);
    path = name;
    open(name, imode);
}
  • 首先会创建一个File对象,用于检查文件路径是否合法。目前仅检查文件路径是否含有Nul(/u0000)。
  • 检查文件操作方式,文件有四种操作方式
模式说明
r以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
rw打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
rwd打开以便读取和写入,这点和rw的操作完全一致,但是只会在cache满或者调用RandomAccessFile.close()的时候才会执行内容同步操作。
rws在"rwd"的基础上对内容同步的要求更加严苛,每write修改一个byte都会直接修改到磁盘中。
  • 创建SecurityManager检查读写文件权限
  • 创建文件描述符
  • 打开文件

获取文件通道

通过getChannel可以获取文件通道,进行文件读写。

public final FileChannel getChannel() {
    synchronized (this) {
        if (channel == null) {
            channel = FileChannelImpl.open(fd, path, true, rw, this);
        }
        return channel;
    }
}

通过FileChannelImpl.open创建一个FileChannelImpl实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值