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讀取的本質——FileInputStream與FileChannel對比
倉促成文,還請指正。 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
JAVA之NIO按行讀取大檔案
做專案過程中遇到要解析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 FileInputStream與FileReader的區別
取數據 內存 字符編碼 緩存 () 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>