使用 java 進行文件拷貝 相信很多人都會用,,不過效率上是否最好呢?
澠池ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!
java NIO 性能提升.
第一種方法:古老的方式
Java代碼
public static long forJava(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
byte[] buffer=new byte[length];
while(true){
int ins=in.read(buffer);
if(ins==-1){
in.close();
out.flush();
out.close();
return new Date().getTime()-time;
}else
out.write(buffer,0,ins);
}
}
public static long forJava(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
byte[] buffer=new byte[length];
while(true){
int ins=in.read(buffer);
if(ins==-1){
in.close();
out.flush();
out.close();
return new Date().getTime()-time;
}else
out.write(buffer,0,ins);
}
}
方法的2參數(shù)分別是原始文件,和拷貝的目的文件.這里不做過多介紹.
實現(xiàn)方法很簡單,分別對2個文件構(gòu)建輸入輸出流,并且使用一個字節(jié)數(shù)組作為我們內(nèi)存的緩存器, 然后使用流從f1 中讀出數(shù)據(jù)到緩存里,在將緩存數(shù)據(jù)寫到f2里面去.這里的緩存是2MB的字節(jié)數(shù)組
第2種方法:使用NIO中的管道到管道傳輸
Java代碼
public static long forTransfer(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
FileChannel inC=in.getChannel();
FileChannel outC=out.getChannel();
int i=0;
while(true){
if(inC.position()==inC.size()){
inC.close();
outC.close();
return new Date().getTime()-time;
}
if((inC.size()-inC.position())20971520)
length=(int)(inC.size()-inC.position());
else
length=20971520;
inC.transferTo(inC.position(),length,outC);
inC.position(inC.position()+length);
i++;
}
}
public static long forTransfer(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
FileChannel inC=in.getChannel();
FileChannel outC=out.getChannel();
int i=0;
while(true){
if(inC.position()==inC.size()){
inC.close();
outC.close();
return new Date().getTime()-time;
}
if((inC.size()-inC.position())20971520)
length=(int)(inC.size()-inC.position());
else
length=20971520;
inC.transferTo(inC.position(),length,outC);
inC.position(inC.position()+length);
i++;
}
}
實現(xiàn)方法:在第一種實現(xiàn)方法基礎上對輸入輸出流獲得其管道,然后分批次的從f1的管道中像f2的管道中輸入數(shù)據(jù)每次輸入的數(shù)據(jù)最大為2MB
方法3:內(nèi)存文件景象寫(讀文件沒有使用文件景象,有興趣的可以回去試試,,我就不試了,估計會更快)
Java代碼
public static long forImage(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
RandomAccessFile out=new RandomAccessFile(f2,"rw");
FileChannel inC=in.getChannel();
MappedByteBuffer outC=null;
MappedByteBuffer inbuffer=null;
byte[] b=new byte[length];
while(true){
if(inC.position()==inC.size()){
inC.close();
outC.force();
out.close();
return new Date().getTime()-time;
}
if((inC.size()-inC.position())length){
length=(int)(inC.size()-inC.position());
}else{
length=20971520;
}
b=new byte[length];
inbuffer=inC.map(MapMode.READ_ONLY,inC.position(),length);
inbuffer.load();
inbuffer.get(b);
outC=out.getChannel().map(MapMode.READ_WRITE,inC.position(),length);
inC.position(b.length+inC.position());
outC.put(b);
outC.force();
}
}
public static long forImage(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
RandomAccessFile out=new RandomAccessFile(f2,"rw");
FileChannel inC=in.getChannel();
MappedByteBuffer outC=null;
MappedByteBuffer inbuffer=null;
byte[] b=new byte[length];
while(true){
if(inC.position()==inC.size()){
inC.close();
outC.force();
out.close();
return new Date().getTime()-time;
}
if((inC.size()-inC.position())length){
length=(int)(inC.size()-inC.position());
}else{
length=20971520;
}
b=new byte[length];
inbuffer=inC.map(MapMode.READ_ONLY,inC.position(),length);
inbuffer.load();
inbuffer.get(b);
outC=out.getChannel().map(MapMode.READ_WRITE,inC.position(),length);
inC.position(b.length+inC.position());
outC.put(b);
outC.force();
}
}
實現(xiàn)方法:跟傷2個例子不一樣,這里寫文件流沒有使用管道而是使用內(nèi)存文件映射(假設文件f2在內(nèi)存中).在循環(huán)中從f1的管道中讀取數(shù)據(jù)到字節(jié)數(shù)組里,然后在像內(nèi)存映射的f2文件中寫數(shù)據(jù).
第4種方法:管道對管道
Java代碼
public static long forChannel(File f1,File f2) throws Exception{
long time=new Date().getTime();
int length=2097152;
FileInputStream in=new FileInputStream(f1);
FileOutputStream out=new FileOutputStream(f2);
FileChannel inC=in.getChannel();
FileChannel outC=out.getChannel();
ByteBuffer b=null;
while(true){
if(inC.position()==inC.size()){
inC.close();
outC.close();
return new Date().getTime()-time;
}
if((inC.size()-inC.position())length){
length=(int)(inC.size()-inC.position());
}else
length=2097152;
b=ByteBuffer.allocateDirect(length);
inC.read(b);
b.flip();
outC.write(b);
outC.force(false);
}
}
注:參數(shù)中的File可以這樣定義:
FIle f1 = new File("C:\\test.dat");
File f2 = new File("D:\\test.dat");
界面上使用這個虛擬路徑,就可以輸出這個圖片或者文件路徑的。
文件從本地到服務器的功能,其實是為了解決目前瀏覽器不支持獲取本地文件全路徑。不得已而想到上傳到服務器的固定目錄,從而方便項目獲取文件,進而使程序支持EXCEL批量導入數(shù)據(jù)。
java中文件上傳到服務器的指定路徑的代碼:
在前臺界面中輸入:
form method="post" enctype="multipart/form-data" ?action="../manage/excelImport.do"
請選文件:input type="file" ?name="excelFile"
input type="submit" value="導入" onclick="return impExcel();"/
/form
action中獲取前臺傳來數(shù)據(jù)并保存
/**
* excel 導入文件
* @return
* @throws IOException
*/
@RequestMapping("/usermanager/excelImport.do")
public String excelImport(
String filePath,
MultipartFile ?excelFile,HttpServletRequest request) throws IOException{
log.info("action:{} Method:{} start","usermanager","excelImport" );
if (excelFile != null){
String filename=excelFile.getOriginalFilename();
String a=request.getRealPath("u/cms/www/201509");
SaveFileFromInputStream(excelFile.getInputStream(),request.getRealPath("u/cms/www/201509"),filename);//保存到服務器的路徑
}
log.info("action:{} Method:{} end","usermanager","excelImport" );
return "";
}
/**
* 將MultipartFile轉(zhuǎn)化為file并保存到服務器上的某地
*/
public void SaveFileFromInputStream(InputStream stream,String path,String savefile) throws IOException
{ ? ?
FileOutputStream fs=new FileOutputStream( path + "/"+ savefile);
System.out.println("------------"+path + "/"+ savefile);
byte[] buffer =new byte[1024*1024];
int bytesum = 0;
int byteread = 0;
while ((byteread=stream.read(buffer))!=-1)
{
bytesum+=byteread;
fs.write(buffer,0,byteread);
fs.flush();
}
fs.close();
stream.close();
}
下面列舉出4種方式:
1、使用FileStreams復制
這是最經(jīng)典的方式將一個文件的內(nèi)容復制到另一個文件中。 使用FileInputStream讀取文件A的字節(jié),使用FileOutputStream寫入到文件B。正如你所看到的我們執(zhí)行幾個讀和寫操作try的數(shù)據(jù),所以這應該是一個低效率的,下一個方法我們將看到新的方式。 這是第一個方法的代碼:
2、使用FileChannel復制
Java NIO包括transferFrom方法,根據(jù)文檔應該比文件流復制的速度更快。 這是第二種方法的代碼:
3、使用Commons IO復制
Apache Commons IO提供拷貝文件方法在其FileUtils類,可用于復制一個文件到另一個地方。它非常方便使用Apache Commons FileUtils類時,您已經(jīng)使用您的項目。基本上,這個類使用Java NIO FileChannel內(nèi)部。 這是第三種方法的代碼:
4、使用Java7的Files類復制
如果你有一些經(jīng)驗在Java 7中你可能會知道,可以使用復制方法的Files類文件,從一個文件復制到另一個文件。 這是第四個方法的代碼: