Java使用内存映射实现大文件的上传

在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验。

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

    }  

}

测试文件为一个大小为1253244字节的文件。测试结果:

sum:220152087 time:1464
sum:220152087 time:72
sum:220152087 time:25

说明读数据无误。删去其中的数据处理部分。
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();
        }  

    }  

}

测试结果:

sum:0 time:1458
sum:0 time:67
sum:0 time:8

由此可见,将文件部分或者全部映射到内存后进行读写,速度将提高很多。

这是因为内存映射文件首先将外存上的文件映射到内存中的一块连续区域,被当成一个字节数组进行处理,读写操作直接对内存进行操作,而后再将内存区域重新映射到外存文件,这就节省了中间频繁的对外存进行读写的时间,大大降低了读写时间。

时间: 2024-11-06 10:39:49

Java使用内存映射实现大文件的上传的相关文章

Java中用内存映射处理大文件

在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验. [java] view plain copy package test; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundExceptio

java大文件分片上传插件

我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,ie8,ie9,Chrome,Firefox,360安全浏览器,并且刷新浏览器后仍然能够续传,重启浏览器(关闭浏览器后再打开)仍然能够继续上传,重启电脑后仍然能够上传 支持文件夹的上传,要求服务端能够保留层级结构,并且能够续传.需要支持10万个以上的文件夹上传. 支持低版本的系统和浏览器,因为这个项目

android下大文件分割上传

由于android自身的原因,对大文件(如影视频文件)的操作很容易造成OOM,即:Dalvik堆内存溢出,利用文件分割将大文件分割为小文件可以解决问题. 文件分割后分多次请求服务. 1 //文件分割上传 2 public void cutFileUpload(String fileType,String filePath) 3 { 4 try 5 { 6 FileAccessI fileAccessI = new FileAccessI(filePath, 0); 7 Long nStartPo

PHP实现大文件的上传设置

打开php.ini,首先找到 ;;;;;;;;;;;;;;;; ; File Uploads ; ;;;;;;;;;;;;;;;; 区域,有影响文件上传的以下几个参数: file_uploads = on ;是否允许通过HTTP上传文件的开关.默认为ON即是开 upload_tmp_dir ;文件上传至服务器上存储临时文件的地方,如果没指 打开php.ini,首先找到;;;;;;;;;;;;;;;;; File Uploads ;;;;;;;;;;;;;;;;;区域,有影响文件上传的以下几个参数

Ajax实现大文件切割上传

Ajax大文件切割上传 2015-02-07 前面我们已经实现了Ajax的文件上传,不过会受限于服务器的允许的大小, 如果服务器并非自己的,我们就要使用Ajax大文件切割来实现上传. 首先解决Ajax跨域上传问题: 在HTML5中,ajax的跨域有了新的规则-----能否跨域取决于对应的应答. 对方服务器如果愿意接受远程过来的ajax,或某几个域名过来的ajax请求,可以在头信息header中,加入Access-Control-Allow-Origin * 在PHP中加入此信息,就可以实现跨域请

iOS大文件分片上传和断点续传

总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件切片(分块),但这不是我们现在说的重点,我们要做的事是保证在网络中断后1G的文件已上传的那部分在下次网络连接时不必再重传.所以我们本地在上传的时候,要将大文件进行分片,比如分成1024*1024B,即将大文件分成1M的片进行上传,服务器在接收后,再将这些片合并成原始文件,这就是分片的基本原理.断点续

Ajax大文件切割上传

1问:在不更改php.ini中post_max_size的情况下怎么实现大文件的上? 答把大文件切割成许多小块,分块上传,传完后,重新合并成大文件即可. 2问:怎么切割? 答:用html5中的file API,这个API继承自Blob对象,Blob中有slice方法,可以截取二进制对象的一部分,实现切割大文件的效果. 3问:具体思路呢? 答:截取10M上传,判断是否截取完毕 while 还有数据{ 截取, Ajax上传 } 1 <script type="text/javascript&q

大文件分片上传,断点续传,秒传 实现

前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长,请求超时:3,传输中断,必须重新上传导致前功尽弃: 解决方案: 1,修改服务端上传的限制配置:Nginx 以及 PHP 的上传文件限制 不宜过大,一般5M 左右为好: 2,大文件分片,一片一片的传到服务端,再由服务端合并.这么做的好处在于一旦上传失败只是损失一个分片而已,不用整个文件重传,而且每个分

大文件分片上传

Vue项目中遇到了大文件分片上传的问题,之前用过webuploader,索性就把Vue2.0与webuploader结合起来使用,封装了一个vue的上传组件,使用起来也比较舒爽. 上传就上传吧,为什么搞得那么麻烦,用分片上传? 分片与并发结合,将一个大文件分割成多块,并发上传,极大地提高大文件的上传速度.当网络问题导致传输错误时,只需要重传出错分片,而不是整个文件.另外分片传输能够更加实时的跟踪上传进度. 实现后的界面: 主要是两个文件,封装的上传组件和具体的ui页面,上传组件代码下面有列出来.