java 文件移动 常规四种方法 和利用FileCopyUtils.copy( , )方法

使用 java 进行文件拷贝 相信很多人都会用,,不过效率上是否最好呢?
最近看了看NIO决定试一试 java  NIO 到底有什么性能的提升.

第一种方法:古老的方式

  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参数分别是原始文件,和拷贝的目的文件.这里不做过多介绍.

实现方法很简单,分别对2个文件构建输入输出流,并且使用一个字节数组作为我们内存的缓存器, 然后使用流从f1 中读出数据到缓存里,在将缓存数据写到f2里面去.这里的缓存是2MB的字节数组

第2种方法:使用NIO中的管道到管道传输

     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
++ ;
        }
    }

实现方法:在第一种实现方法基础上对输入输出流获得其管道,然后分批次的从f1的管道中像f2的管道中输入数据每次输入的数据最大为2MB

方法3:内存文件景象写(读文件没有使用文件景象,有兴趣的可以回去试试,,我就不试了,估计会更快)

     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();
        }
    }

实现方法:跟伤2个例子不一样,这里写文件流没有使用管道而是使用内存文件映射(假设文件f2在内存中).在循环中从f1的管道中读取数据到字节数组里,然后在像内存映射的f2文件中写数据.

第4种方法:管道对管道

     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 );
        }
    }

这里实现方式与第3种实现方式很类似,不过没有使用内存影射.

 

下面是对49.3MB的文件进行拷贝的测试时间(毫秒)

Start Copy File...  file size:50290KB
CopyFile:b1.rmvb mode:forChannel  RunTime:3203
CopyFile:b1.rmvb mode:forImage  RunTime:3328
CopyFile:b1.rmvb mode:forJava  RunTime:2172
CopyFile:b1.rmvb mode:forTransfer RunTime:1406
End Copy File!





PS:这个一个上传方法 用的uploadify插件

public ReturnObject uploadFile(String deleteFileName,
            HttpServletRequest request,HttpServletResponse response)
            throws IOException{
        System.out.println("附件上传sessionInfo:"
                + ContextUtils.getSession().getId());
        String basePath = Global.BASE_UPLOAD_FOLDER; // 获取基础路径
        String TemporaryFile=Global.BASE_UPLOAD_TEMPORARYFILE;//获取临时文件夹
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
        Map<String,MultipartFile> fileMap = multipartRequest.getFileMap();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
        SimpleDateFormat sp = new SimpleDateFormat("yyyyMMdd");
        // TODO multi-tenant.id 目前租户ID都是707 待以后完善后multi-tenant.id 就是租户ID
        String ctxPath = basePath + File.separator + 707 + File.separator
                + ContextUtils.getCurrentSecurityUser().getUsername()
                + File.separator+TemporaryFile+File.separator;// 完整路径
        String ctxPathView = sp.format(new Date()) + "/";// 用于在数据库存储的路径-从文件夹开始
        String ymd = sdf.format(new Date());
        // 如果不存在,创建文件夹
        File file = new File(ctxPath);
        if (!file.exists()){
            file.mkdirs();
        }
        ReturnObject ro = new ReturnObject();
        String fileNames = "";
        for (Map.Entry<String,MultipartFile> entity : fileMap.entrySet()){
            MultipartFile mf = entity.getValue();
            String fileFullname = mf.getOriginalFilename();
            // String fileName = mf.getOriginalFilename();
            String fileName = ymd + "_" + fileFullname;
            File uploadFile = new File(ctxPath + fileName);
            try{
                FileCopyUtils.copy(mf.getBytes(),uploadFile); //可以利用此方法进行文件移动,通过流直接移动
                // copy成功之后保存上传数据记录
                UploadFile uploadBean = new UploadFile();
                uploadBean.setUpdUser(ContextUtils.getCurrentSecurityUser()
                        .getUsername());
                uploadBean.setOriginName(fileFullname);
                uploadBean.setFileName(fileName);
                uploadBean.setUpdTime(new Date());
                uploadBean.setIsFunction("other");
                if (uploadBean != null){
                    uploadFileService.save(uploadBean);
                }
                fileNames += fileName + ",";
            }
            catch (IOException e){
                e.printStackTrace();
                ro.setSuccess(false);
                ro.setMsg(e.getMessage());
                return ro;
            }
        }
        if (fileNames.endsWith(",")){
            fileNames = fileNames.substring(0,fileNames.length() - 1);
        }
        ro.setSuccess(true);
        ro.setMsg("上传文件成功");
        HashMap<String,Object> hsfiled = new HashMap<String,Object>();
        hsfiled.put("fileNames",fileNames);
        hsfiled.put("filepatch",ctxPathView);// 数据库保存路径(从时间开始截取的)
        ro.setObj(hsfiled);
        // 清空不需要的历史文件
        try{
            log.info("删除不需要的文件:" + deleteFileName);
            String ctPath = basePath + File.separator + File.separator
                    + deleteFileName;
            // 如果不存在,创建文件夹
            if (deleteFileName != null){
                File fileTobeDelete = new File(ctPath);
                if (fileTobeDelete.exists()){
                    fileTobeDelete.delete();
                }
            }
        }
        catch (Exception e){
            log.error("删除历史文件出错:" + e.getMessage());
        }
        return ro;
    }

你可能感兴趣的:(java,上传,文件移动)