Java中使用內(nèi)存映射實(shí)現(xiàn)大文件上傳實(shí)例
在處理大文件時(shí),如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 來(lái)進(jìn)行頻繁的讀寫(xiě)操作,都將導(dǎo)致進(jìn)程因頻繁讀寫(xiě)外存而降低速度.如下為一個(gè)對(duì)比實(shí)驗(yàn)。
package test;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) {
try {
FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
int sum=0;
int n;
long t1=System.currentTimeMillis();
try {
while((n=fis.read())>=0){
sum+=n;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long t=System.currentTimeMillis()-t1;
System.out.println("sum:"+sum+" time:"+t);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
int sum=0;
int n;
long t1=System.currentTimeMillis();
try {
while((n=bis.read())>=0){
sum+=n;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long t=System.currentTimeMillis()-t1;
System.out.println("sum:"+sum+" time:"+t);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MappedByteBuffer buffer=null;
try {
buffer=new RandomAccessFile("/home/tobacco/test/res.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);
int sum=0;
int n;
long t1=System.currentTimeMillis();
for(int i=0;i<1253244;i++){
n=0x000000ff&buffer.get(i);
sum+=n;
}
long t=System.currentTimeMillis()-t1;
System.out.println("sum:"+sum+" time:"+t);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
測(cè)試文件為一個(gè)大小為1253244字節(jié)的文件。測(cè)試結(jié)果:
sum:220152087 time:1464
sum:220152087 time:72
sum:220152087 time:25
說(shuō)明讀數(shù)據(jù)無(wú)誤。刪去其中的數(shù)據(jù)處理部分。
package test;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class Test {
public static void main(String[] args) {
try {
FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
int sum=0;
int n;
long t1=System.currentTimeMillis();
try {
while((n=fis.read())>=0){
//sum+=n;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long t=System.currentTimeMillis()-t1;
System.out.println("sum:"+sum+" time:"+t);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
FileInputStream fis=new FileInputStream("/home/tobacco/test/res.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
int sum=0;
int n;
long t1=System.currentTimeMillis();
try {
while((n=bis.read())>=0){
//sum+=n;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long t=System.currentTimeMillis()-t1;
System.out.println("sum:"+sum+" time:"+t);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MappedByteBuffer buffer=null;
try {
buffer=new RandomAccessFile("/home/tobacco/test/res.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);
int sum=0;
int n;
long t1=System.currentTimeMillis();
for(int i=0;i<1253244;i++){
//n=0x000000ff&buffer.get(i);
//sum+=n;
}
long t=System.currentTimeMillis()-t1;
System.out.println("sum:"+sum+" time:"+t);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
測(cè)試結(jié)果:
sum:0 time:1458
sum:0 time:67
sum:0 time:8
由此可見(jiàn),將文件部分或者全部映射到內(nèi)存后進(jìn)行讀寫(xiě),速度將提高很多。
這是因?yàn)閮?nèi)存映射文件首先將外存上的文件映射到內(nèi)存中的一塊連續(xù)區(qū)域,被當(dāng)成一個(gè)字節(jié)數(shù)組進(jìn)行處理,讀寫(xiě)操作直接對(duì)內(nèi)存進(jìn)行操作,而后再將內(nèi)存區(qū)域重新映射到外存文件,這就節(jié)省了中間頻繁的對(duì)外存進(jìn)行讀寫(xiě)的時(shí)間,大大降低了讀寫(xiě)時(shí)間。
相關(guān)文章
java 實(shí)現(xiàn)websocket的兩種方式實(shí)例詳解
這篇文章主要介紹了java 實(shí)現(xiàn)websocket的兩種方式實(shí)例詳解,一種使用tomcat的websocket實(shí)現(xiàn),一種使用spring的websocket,本文通過(guò)代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2018-07-07Spring?Security實(shí)現(xiàn)基于RBAC的權(quán)限表達(dá)式動(dòng)態(tài)訪問(wèn)控制的操作方法
這篇文章主要介紹了Spring?Security實(shí)現(xiàn)基于RBAC的權(quán)限表達(dá)式動(dòng)態(tài)訪問(wèn)控制,資源權(quán)限表達(dá)式動(dòng)態(tài)權(quán)限控制在Spring Security也是可以實(shí)現(xiàn)的,首先開(kāi)啟方法級(jí)別的注解安全控制,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04Mybatis-Plus可能導(dǎo)致死鎖的問(wèn)題分析及解決辦法
這篇文章給大家主要介紹了Mybatis-Plus可能導(dǎo)致死鎖的問(wèn)題分析及解決辦法,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2023-12-12Java自定義類(lèi)加載器實(shí)現(xiàn)類(lèi)隔離詳解
由于每種組件的不同版本所依賴(lài)的jar包不同,我們可以借鑒tomcat的實(shí)現(xiàn)方式,通過(guò)自定義類(lèi)加載器打破雙親委派機(jī)制來(lái)實(shí)現(xiàn)類(lèi)隔離,從而達(dá)到操作多組件多版本的目的。本文就來(lái)和大家詳細(xì)聊聊實(shí)現(xiàn)方法2023-03-03Java發(fā)送報(bào)文與接收?qǐng)?bào)文的實(shí)例代碼
這篇文章主要介紹了Java發(fā)送報(bào)文與接收?qǐng)?bào)文,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03在安卓系統(tǒng)中插入表情到光標(biāo)位置的代碼詳解
這篇文章主要介紹了在安卓系統(tǒng)中插入表情到光標(biāo)位置的代碼詳解,利用Java代碼在EditText控件中實(shí)現(xiàn),需要的朋友可以參考下2015-07-07