1. 程式人生 > >Java檔案NIO讀取的本質——FileInputStream與FileChannel對比

Java檔案NIO讀取的本質——FileInputStream與FileChannel對比

倉促成文,還請指正。

FileInputStream典型程式碼

    public static void main(String[] args) {
        System.out.println(System.getProperty("user.dir"));
        File file = new File(System.getProperty("user.dir") + "/src/oio/file.txt");
        System.out.println("file name: " + file.getName());

        InputStream inputStream = null
; try { inputStream = new FileInputStream(file); byte[] bytes = new byte[(int) file.length()]; int len = inputStream.read(bytes); System.out.println("bytes len :" + len + " detail: " + new String(bytes)); } catch (IOException e) { e.printStackTrace(); if
(inputStream != null) { try { inputStream.close(); } catch (IOException e1) { e1.printStackTrace(); } } } }

FileChannel典型程式碼

public class NIOTest {

    public static void main(String[] args) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(4
);//① Path path = Paths.get(System.getProperty("user.dir") + "/assets/file.txt"); FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);//② int len = fileChannel.read(byteBuffer);//③ while (len != -1) { byteBuffer.flip();//④ while (byteBuffer.hasRemaining()){ System.out.print((char) byteBuffer.get());//⑤ } byteBuffer.clear();//⑥ len = fileChannel.read(byteBuffer);//⑦ } } }

FileInputStream和FileChannel的深度分析

FileInputStream的read方法,呼叫了native的read0

jint
readSingle(JNIEnv *env, jobject this, jfieldID fid) {
    jint nread;
    char ret;
    FD fd = GET_FD(this, fid);
    if (fd == -1) {
        JNU_ThrowIOException(env, "Stream Closed");
        return -1;
    }
    nread = IO_Read(fd, &ret, 1);
    if (nread == 0) { /* EOF */
        return -1;
    } else if (nread == -1) { /* error */
        JNU_ThrowIOExceptionWithLastError(env, "Read error");
    }
    return ret & 0xFF;
}

核心是IO_Read方法。

#define IO_Read handleRead
JNIEXPORT
jint
handleRead(FD fd, void *buf, jint len)
{
    DWORD read = 0;
    BOOL result = 0;
    HANDLE h = (HANDLE)fd;
    if (h == INVALID_HANDLE_VALUE) {
        return -1;
    }
    result = ReadFile(h,          /* File handle to read */
                      buf,        /* address to put data */
                      len,        /* number of bytes to read */
                      &read,      /* number of bytes read */
                      NULL);      /* no overlapped struct */
    if (result == 0) {
        int error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            return 0; /* EOF */
        }
        return -1;
    }
    return (jint)read;
}

核心方法是ReadFile方法。

FileChannel的read方法

1.使用FIleChannelImpl作為FileChannel的實現類,read方法:

   public int read(ByteBuffer dst) throws IOException {
        ensureOpen();
        if (!readable)
            throw new NonReadableChannelException();
        synchronized (positionLock) {
            int n = 0;
            int ti = -1;
            try {
                begin();
                ti = threads.add();
                if (!isOpen())
                    return 0;
                do {
                    n = IOUtil.read(fd, dst, -1, nd);
                } while ((n == IOStatus.INTERRUPTED) && isOpen());
                return IOStatus.normalize(n);
            } finally {
                threads.remove(ti);
                end(n > 0);
                assert IOStatus.check(n);
            }
        }
    }

核心方法是IOUtil.read。

2.進入IOUtil類:

    static int read(FileDescriptor fd, ByteBuffer dst, long position,
                    NativeDispatcher nd)
        throws IOException
    {
        if (dst.isReadOnly())
            throw new IllegalArgumentException("Read-only buffer");
        if (dst instanceof DirectBuffer)
            return readIntoNativeBuffer(fd, dst, position, nd);

        // Substitute a native buffer
        ByteBuffer bb = Util.getTemporaryDirectBuffer(dst.remaining());
        try {
            int n = readIntoNativeBuffer(fd, bb, position, nd);
            bb.flip();
            if (n > 0)
                dst.put(bb);
            return n;
        } finally {
            Util.offerFirstTemporaryDirectBuffer(bb);
        }
    }

核心方法是readIntoNativeBuffer。

3.進入readIntoNativeBuffer方法

    private static int readIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
                                            long position, NativeDispatcher nd)
        throws IOException
    {
        int pos = bb.position();
        int lim = bb.limit();
        assert (pos <= lim);
        int rem = (pos <= lim ? lim - pos : 0);

        if (rem == 0)
            return 0;
        int n = 0;
        if (position != -1) {
            n = nd.pread(fd, ((DirectBuffer)bb).address() + pos,
                         rem, position);
        } else {
            n = nd.read(fd, ((DirectBuffer)bb).address() + pos, rem);
        }
        if (n > 0)
            bb.position(pos + n);
        return n;
    }

核心方法是nd.pread(或nd.read,本質上一樣)。這裡的nd是抽象類sun.nio.ch.NativeDispatcher,具體類是sun.nio.ch.FileDispatcherImpl

4.進入sun.nio.ch.FileDispatcherImpl類:

    int read(FileDescriptor var1, long var2, int var4) throws IOException {
        return read0(var1, var2, var4);
    }

最終進入了一個native的read0方法。

JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, jobject fdo,
                                      jlong address, jint len)
{
    DWORD read = 0;
    BOOL result = 0;
    HANDLE h = (HANDLE)(handleval(env, fdo));

    if (h == INVALID_HANDLE_VALUE) {
        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
        return IOS_THROWN;
    }
    result = ReadFile(h,          /* File handle to read */
                      (LPVOID)address,    /* address to put data */
                      len,        /* number of bytes to read */
                      &read,      /* number of bytes read */
                      NULL);      /* no overlapped struct */
    if (result == 0) {
        int error = GetLastError();
        if (error == ERROR_BROKEN_PIPE) {
            return IOS_EOF;
        }
        if (error == ERROR_NO_DATA) {
            return IOS_UNAVAILABLE;
        }
        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
        return IOS_THROWN;
    }
    return convertReturnVal(env, (jint)read, JNI_TRUE);
}

核心方法是ReadFile方法。

結論

FileInputStream和FileChannel最終均呼叫了native的ReadFile方法,本質是一樣的!

相關推薦

Java檔案NIO讀取本質——FileInputStreamFileChannel對比

倉促成文,還請指正。 FileInputStream典型程式碼 public static void main(String[] args) { System.out.println(System.getPropert

java檔案上傳至伺服器檔案的刪除

一、檔案上傳(到伺服器中)程式碼如下: /** * 上傳檔案 * @param file 檔案 * @param request HttpServletRequest * @return 返回檔案基本資訊 */

檔案讀取圖片,從資料庫表中讀取圖片評測

一、在 d:\ 下建立 image 資料夾,再放10 張圖片, 名稱從 1.png 到 10.png . 二、先建立新庫 db1, 然後按下面指令碼建立初始環境: USE db1 GO IF OBJECT_ID('t_path') IS NOT NULL DROP TABLE t_pat

Java之路:抽象類介面對比

先上圖: 下面詳細說下: 1、相同點 (1)都是抽象型別; (2)都可以有實現方法;抽象類中可以實現普通方法,介面中可以實現預設方法(Java 8)。 (3) 都可以不需要實現類或者繼承者去實現所有方法。(以前不行,現在介面中預設方法不需

Java多種IO方式的實現效能對比

一、概述:(1)Input:這個input是對計算機記憶體而言的,也就是從外部檔案讀取資訊到記憶體中,採用了五種方式(2)Output:這個Output是對計算機記憶體而言的,也就是從將資訊寫入外部檔案,採用了四種方式二、具體實現:(1)InputA、    InputStr

java爬取鬥魚:虎牙對比

看了下鬥魚的基礎頁面,感覺和虎牙的有點像,但是實際上確有點不同。 首先想要獲取頁數,看了鬥魚的html頁面,發現卻不顯示頁面。 這是因為鬥魚把介面藏在了js頁面中,谷歌瀏覽器的右擊檢查 那麼接下來就是選取一款可以解析js的工具並且提取裡面的資訊了。

Java配置檔案Properties的讀取、寫入更新操作

/**   * 實現對Java配置檔案Properties的讀取、寫入與更新操作   */    package test;     &nbs

java nio 實現檔案讀取和輸出

1、讀取檔案流     File f= new File("**");     FileInputStream in=new FileInputStream(f);     //獲取輸入管道     FileChannel inChannel=in.getChannel()

java web開發實現properties檔案讀取解析

        在java web 開發的過程當中,由於涉及到附件的上傳,這樣就必然需要設定檔案的路徑,如果在程式碼中寫死檔案上傳的路徑,必然是不合理的。那麼通常的做法就是將相關設定放在配置檔案當中,

java檔案內容:讀取寫入

對於java檔案讀取一直比較迷糊,整理了下,日後可以直接翻看。 package baixiaosheng; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import ja

JAVANIO按行讀取檔案

        做專案過程中遇到要解析100多M的TXT檔案,併入庫。用之前的FileInputStream、BufferedReader顯然不行了,雖然readLine這方法可以直接按行讀取,但是去讀一個140M左右,68W條資料的檔案時,不但耗時長而且會記憶體溢位,即你

JAVA NIO(三) 三種檔案的複製方法效率對比

檔案的複製最能體現io效率了.因為既需要讀取資料還需要寫出到硬碟中,下面提供了三種檔案複製的方法 可以對比一下 直接緩衝區與非直接緩衝區的效率對比.public class Nio { public static void main(String[] args) t

JAVA FileInputStream BufferedInputStream讀取效率的比較

通過BufferedInputStream讀取用時:114;通過InputStream讀取用時:1283 網友的疑問是,為什麼我們用了buffer(BufferedInputStream )花的時間還比沒用的時候長? 首先我們關注他們的讀取: in.read(b,0,8000) in read(byte

java文件讀取寫入

文件 public color exc cnblogs 循環 pack delet 根據 package com.myjava; import java.io.*; import java.util.ArrayList; import java.util.Collect

Java FileInputStreamFileReader的區別

取數據 內存 字符編碼 緩存 () print out main 阻塞 在解釋Java中FileInputStream和FileReader的具體區別之前,我想講述一下Java中InputStream和Reader的根本差異,以及分別什麽時候使用InputStream和Re

java nio讀取和寫入文件

文件 pri system [] gif write pack sts row 讀取 package com.test; import java.io.File; import java.io.FileInputStream; import java.i

Java NIO 讀取文件、寫入文件、讀取寫入混合

ID text forname tac 之間 fin top put HR 前言 Java NIO(new/inputstream outputstream)使用通道、緩沖來操作流,所以要深刻理解這些概念,尤其是,緩沖中的數據結構(當前位置(position)、限制(lim

第一章 java nio三大組件使用姿勢

鏈路 循環 true tro 進程 案例 [] ase system 本案例來源於《netty權威指南》 一、三大組件 Selector:多路復用器。輪詢註冊在其上的Channel,當發現某個或者多個Channel處於“就緒狀態”後(accept接收連接事件、connec

java小程式讀取檔案獲取檔案有用資訊

import java.util.regex.*; import java.io.*; import java.lang.*; public class GainNumber{ public static void main(String[]args)throws Exception

java實現json檔案讀取和解析

<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId>