java FileInputStream open0原始碼解析

zhanghl111發表於2020-11-04

這裡寫目錄標題

一級目錄

本文的jdk原始碼為openjdk1.8。在java中對File類來表示檔案,但是File類並沒有inputStream和outputStream來對檔案輸入輸出進行操作,在java中檔案的輸入輸出功能交由FileInputStream和FileOutputStream兩個類來進行。

    public FileInputStream(File file) throws FileNotFoundException {
        String name = (file != null ? file.getPath() : null);
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkRead(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);
    }

	    /**
     * Opens the specified file for reading.
     * @param name the name of the file
     */
    private void open(String name) throws FileNotFoundException {
        open0(name);
    }

	/**
     * Opens the specified file for reading.
     * @param name the name of the file
     */
    private native void open0(String name) throws FileNotFoundException;

FileInputStream建構函式通過輸入File來進行構造,其中的file通過open來開啟,open方法通過呼叫open0來執行開啟方法,open0是native方法。

open0的方法定義在openjdk\jdk\src\share\native\java\io\FileInputStream.c中

JNIEXPORT void JNICALL
Java_java_io_FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
    fileOpen(env, this, path, fis_fd, O_RDONLY);
}

windows環境下fileOpen函式在openjdk\jdk\src\windows\native\java\io\io_util_md.c中

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)
{
    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 overrides O_CREAT */
        (flags & O_TRUNC) ? CREATE_ALWAYS :
        (flags & O_CREAT) ? OPEN_ALWAYS   :
        OPEN_EXISTING;
    const DWORD  maybeWriteThrough =
        (flags & (O_SYNC | O_DSYNC)) ?
        FILE_FLAG_WRITE_THROUGH :
        FILE_ATTRIBUTE_NORMAL;
    const DWORD maybeDeleteOnClose =
        (flags & O_TEMPORARY) ?
        FILE_FLAG_DELETE_ON_CLOSE :
        FILE_ATTRIBUTE_NORMAL;
    const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
    HANDLE h = NULL;

    WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE);
    if (pathbuf == NULL) {
        /* Exception already pending */
        return -1;
    }
    h = CreateFileW(
        pathbuf,            /* Wide char path name */
        access,             /* Read and/or write permission */
        sharing,            /* File sharing flags */
        NULL,               /* Security attributes */
        disposition,        /* creation disposition */
        flagsAndAttributes, /* flags and attributes */
        NULL);
    free(pathbuf);

    if (h == INVALID_HANDLE_VALUE) {
        throwFileNotFoundException(env, path);
        return -1;
    }
    return (jlong) h;
}

在fileOpen方法中主要是呼叫winFileHandleOpen方法,通過該方法返回的Handle來判斷是否開啟成功,如果成功就對FD(fileDescription檔案描述符)進行設定,如果不存在失敗則位元組返回。在winFileHandleOpen中通過flag來判斷檔案開啟後的許可權。在winFileHandleOpen中通過對flag的一系列許可權的判斷來確定檔案的許可權,在Java_java_io_FileInputStream_open0中設定檔案為O_RDONLY,在winFileHandleOpen中檔案以GENERIC_READ許可權開啟,GENERIC_READ表示允許對裝置(檔案)進行讀訪問。最後通過SET_FD()將檔案的控制程式碼進行儲存到呼叫該方法的物件中,就是java中FileDescriptor類的fd,用於後面的檔案的操作。

相關文章