JavaIO怎么调用WindowsAPI的——从Native层剖析JavaIO文件读写

本文探讨了Java中的RandomAccessFile如何通过Windows API进行文件读写操作,详细解析了open、read、write、seek和getFilePointer等方法的native层实现,并与C语言文件操作进行了对比。同时,文章还分析了FileInputStream和FileOutputStream的native方法,展示了它们如何在底层调用Windows API完成文件流操作。
摘要由CSDN通过智能技术生成

上一篇文章中列举了JavaIO中FileDescriptor和File类提供的一些文件操作,这些操作还只是对文件系统中的文件进行创建或删除操作。鉴于大一玩过Window编程(对Linux API不是很熟悉),所以这篇文章会从Windows C API去分析一下Java提供给我们的几个文件读写类。

建议结合着源代码看这篇文章(这篇文章就是记录我看源代码的过程,这里的java版本是1.8.0_131)

RandomAccessFile

这个类就是完全模仿C语言的文件读写操作,允许随机读取,想读文件的哪个部分就可以把文件流指针指到哪儿。下面会列一张表将这个类中的常用方法和标准C语言API进行对比,然后再看一下Java在Native层是怎么实现这个类的:

Java C
public int read(byte b[], int off, int len)
public int read(byte b[])
public final void readFully(byte b[])
public final void readFully(byte b[], int off, int len)
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
public int read() int fgetc( FILE *stream );
int getc( FILE *stream );
public void write(byte b[])
public void write(byte b[], int off, int len)
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
public void write(int b) int fputc( int ch, FILE *stream );
int putc( int ch, FILE *stream );
public void seek(long pos)
public int skipBytes(int n)
int fseek( FILE *stream, long offset, int origin );
int fsetpos( FILE *stream, const fpos_t *pos );
void rewind(FILE *stream);
public native long getFilePointer() long ftell( FILE *stream );
int fgetpos( FILE *stream, fpos_t *pos );

RandomAccessFile还同时实现了DataOutput, DataInput两个接口,所以同时拥有了DataInputStreamDataOutputStream两个类的基本方法。

RandomAccessFile

open

    // 首先从构造方法开始看
    public RandomAccessFile(String name, String mode)
        throws FileNotFoundException
    {
        this(name != null ? new File(name) : null, mode);
    }
    // mode参数指定文件的打开模式
    public RandomAccessFile(File file, String mode)
        throws FileNotFoundException
    {
        String name = (file != null ? file.getPath() : null);
        int imode = -1;
        // r 表示“只读”,调用写操作将会抛出IO异常
        if (mode.equals("r"))
            imode = O_RDONLY;
        // rw 表示“可读可写”,如果文件不存在就会创建它
        else if (mode.startsWith("rw")) {
            imode = O_RDWR;
            rw = true;
            if (mode.length() > 2) {
                // rws 表示每一次写入操作文件内容(content)或元数据(metadata),
                // 底层存储设备也会同步写入
                if (mode.equals("rws"))
                    imode |= O_SYNC;
                // rws 表示每一次写入操作文件内容(content)
                // 底层存储设备也会同步写入
                else if (mode.equals("rwd"))
                    imode |= O_DSYNC;
                else
                    imode = -1;
                // “rwd”模式可用于减少执行的I / O操作的数量。
                // 使用“rwd”更新时只要写入文件内容;
                // 使用“rws”更新时要写入文件内容以及文件元数据(文件大小,文件名等信息),
                // 而文件元数据的更新,通常需要至少一个底层IO操作
            }
        }
        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;
        // 最终辗转调用native方法
        open(name, imode);
    }
    private void open(String name, int mode)
        throws FileNotFoundException {
        open0(name, mode);
    }
    // 最终的native方法
    private native void open0(String name, int mode)
        throws FileNotFoundException;

下面看一下native层是怎么打开文件的:

/
// RandomAccessFile.c文件
JNIEXPORT void JNICALL
Java_java_io_RandomAccessFile_open(JNIEnv *env,
                                   jobject this, jstring path, jint mode)
{
    int flags = 0;
    // 构造标志位
    if (mode & java_io_RandomAccessFile_O_RDONLY)
        flags = O_RDONLY;
    else if (mode & java_io_RandomAccessFile_O_RDWR) {
        flags = O_RDWR | O_CREAT;
        if (mode & java_io_RandomAccessFile_O_SYNC)
            flags |= O_SYNC;
        else if (mode & java_io_RandomAccessFile_O_DSYNC)
            flags |= O_DSYNC;
    }
    // fileOpen
    fileOpen(env, this, path, raf_fd, flags);
}


/
// io_util_md.c文件
// 这里看的windows上的实现
void
fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags)
{
    FD h = winFileHandleOpen(env, path, flags);
    if (h >= 0) {
        SET_FD(this, h, fid);
    }
}

FD
winFileHandleOpen(JNIEnv *env, jstring path, int flags)
{
    // 将标志位解析成Windows API中规定的标志位
    const DWORD access =
        (flags & O_WRONLY) ?  GENERIC_WRITE :
        (flags & O_RDWR)   ? (GENERIC_READ | GENERIC_WRITE) :
        GENERIC_READ;
    const DWORD sharing =
        FILE_SHARE_READ | FILE_SHARE_WRITE;
    const DWORD disposition =
        /* Note: O_TRUNC ove
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值