A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黑马---邢志伟 初级黑马   /  2012-6-26 09:18  /  2704 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

编写程序拷贝一个文件. 尽量使用效率高的方式。这个不是太懂。麻烦高手讲解一下。。。:#

7 个回复

倒序浏览
本帖最后由 韦念欣 于 2012-6-26 09:24 编辑

为了提高性能,先把数据写到内存中的缓冲区中,也可理解为先写到输出流中,当缓冲满的时候,才会将数据写到硬盘上的文件。之所以这样能提升性能,是因为CPU向内存中写数据的速度远远大于直接写到硬盘的速度,缓冲区正是匹配了高速度的CPU和低速的磁盘文件

可以申请一个临时的数组
byte[] buf = new byte[1024];
这个起到临时存储功能的数组当然可以看作缓冲区.

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
看下毕老师IO流的讲解。就知道了!
回复 使用道具 举报
class  IOForCopy
{
        public static void main(String[] args)throws IOException
        {
               
                iocopy("1.txt","1复件txt");
       
        }
        public static void iocopy(String toRead,String toCopy)throws IOException
        {
                BufferedWriter bw=null;
                BufferedReader br=null;
               
                try
                {
                        br=new BufferedReader(new FileReader(toRead));
                        bw=new BufferedWriter(new FileWriter(toCopy));
                       
                        String line=null;
                        while((line=br.readLine())!=null)
                        {
                                bw.write(line);
                                bw.newLine();
                                bw.flush();
                        }
                }
                catch (Exception e)
                {
                        throw new IOException("找不到文件");
                }
                finally
                {
                       
                        try
                        {
                                if (br!=null)
                                br.close();
                        }
                        catch (Exception e)
                        {
                                throw new IOException("读取流关闭失败");
                        }
                        try
                        {
                                if (bw!=null)
                                bw.close();
                        }
                        catch (Exception e)
                        {
                                throw new IOException("写入流关闭失败");
                        }
                }
        }
}

点评

注释啊亲,注释要坚持写  发表于 2012-6-28 22:40
回复 使用道具 举报
使用 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!

解释: 在测试结果中看到 古老方式,和管道向管道传输是最快的,,,,,为什么呢?

我分析是这样的,由于另外2种方法内部都使用了 字节数组作为缓存中转,在加上NIO内部有一个贴近系统的缓存区,这无意就增加了另一个缓存器,所以相对于这2个方法就要慢许多,,如果不使用 字节数组作为数据中转的话相信速度会更快的..

摘自CSDN.

点评

诚实的人我喜欢,找资料也要辛苦费的嘛  发表于 2012-6-28 22:41

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
给你想要的
public static void Copy(File file1,File file2)
{
        BufferedInputStream f1 = null;
        BufferedOutputStream f2 = null;
        try {
                f1 = new BufferedInputStream(new FileInputStream(file1));
                f2 = new BufferedOutputStream(new FileOutputStream(file2));
                while(f1.available()!=0)
                {
                        f2.write(f1.read());
                }
        }
        catch (Exception e)
        {
                e.printStackTrace();
        }
        finally
        {
                if(f1!=null)
                {
                        try
                        {
                                f1.close();
                                f1 = null;
                        }
                        catch (IOException e)
                        {
                                e.printStackTrace();
                        }
                }
                if(f2!=null)
                {
                        try
                        {
                                f2.close();
                                f2 = null;
                        }
                        catch (IOException e)
                        {
                                e.printStackTrace();
                        }
                }
        }
}

点评

注释,讲解,人家不会你直接贴代码。。。。  发表于 2012-6-28 22:42
回复 使用道具 举报
所谓高效率就是让字符写到缓冲池当中,这样就不用读一个字节写一个字节了
只要记住 这样两句最简单的就行
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("文件路径")));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileoutputStream("文件路径")));
然后就是内部的循环了
String line = null;
                while ((line = br.readLine()) != null) {

                        bw.write(line );
                        //换行 可以用bufferReader的newLine
                        bw.newLine();
                        bw.flush();
                                        }

点评

尽量别用字符流,除非你掌握的很彻底  发表于 2012-6-28 22:43
回复 使用道具 举报
明白一些了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马