多线程拷贝文件比较慢? 求帮忙分析

本贴最后更新于 2927 天前,其中的信息可能已经时移世异
package com.pangwen.usefultools.io; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; /** * 文件拷贝工具类 * Created on 2017/4/18. * * @author pangwen * @version 0.1 */public final class FileCopyUtils { /** * 大于500M的文件为大文件 */ private static final long BIG_FILE_SIZE = 1024 * 1024 * 500; /** * byte[]默认长度为1024 */ private static final int BUFFER_SIZE = 1024; /** * 最大线程数 */ private static final int MAX_THREAD_NUM = 5; /** * 静态内部类实现多线程 */ private static class FileCopyWorker implements Runnable { private final File srcFile; private final File targetFile; private final long startPosition; private final long endPosition; /** * constructor * * @param srcFile 源文件 * @param targetFile 目标文件 * @param startPosition 文件开始位置 * @param endPosition 文件结束位置 */ public FileCopyWorker(final File srcFile, final File targetFile, final long startPosition, final long endPosition) { this.srcFile = srcFile; this.targetFile = targetFile; this.startPosition = startPosition; this.endPosition = endPosition; } //@Override public void run() { RandomAccessFile rin = null; RandomAccessFile rout = null; try { rin = new RandomAccessFile(srcFile, "r"); rin.seek(startPosition); rout = new RandomAccessFile(targetFile, "rw"); rout.seek(startPosition); byte[] buffer = new byte[BUFFER_SIZE]; int i; int readLength = 0; while ((i = rin.read(buffer)) != -1 && startPosition + readLength <= endPosition) { rout.write(buffer, 0, i); readLength += i; } } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != rin) rin.close(); } catch (Exception e) { e.printStackTrace(); } try { if (null != rout) rout.close(); } catch (Exception e) { e.printStackTrace(); } } } } /** * nio拷贝文件 * * @param srcFile 源文件 * @param targetFile 目标文件 */ public static void copyFileNio(final File srcFile, final File targetFile) throws FileNotFoundException { if (null == srcFile) throw new FileNotFoundException("src file not found!"); makeParentDirs(targetFile); FileInputStream in = new FileInputStream(srcFile); FileOutputStream out = new FileOutputStream(targetFile); //获取通道 FileChannel inChannel = null; FileChannel outChannel = null; try { inChannel = in.getChannel(); outChannel = out.getChannel(); //创建缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); //将数据读入缓冲区 while (inChannel.read(buffer) != -1) { //flip() 方法让缓冲区可以将新读入的数据写入另一个通道。 buffer.flip(); //将缓冲区数据写入文件 outChannel.write(buffer); //clear() 方法重设缓冲区,使它可以接受读入的数据。 buffer.clear(); } } catch (IOException e) { e.printStackTrace(); } finally { if (inChannel != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (outChannel != null) { try { outChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 拷贝文件 * * @param srcFile 源文件 * @param targetFile 目标文件 * @param allowMultipleThread 是否开启多线程 * @throws FileNotFoundException */ public static void copyFile(final File srcFile, final File targetFile, final boolean allowMultipleThread) throws FileNotFoundException { if (null == srcFile) throw new FileNotFoundException("src file not found!"); //创建父文件夹 makeParentDirs(targetFile); long srcFileLength = srcFile.length(); if (allowMultipleThread && srcFileLength > BIG_FILE_SIZE) { try { //大文件调用多线程 copyFileMultipleThread(srcFile, targetFile); return; } catch (Exception e) { e.printStackTrace(); //多线程拷贝文件失败时调用单线程拷贝文件 copyFile(srcFile, targetFile, false); } } FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream(srcFile); out = new FileOutputStream(targetFile); byte[] buffer = new byte[BUFFER_SIZE]; int i; while ((i = in.read(buffer)) != -1) { out.write(buffer, 0, i); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != in) in.close(); } catch (Exception e) { e.printStackTrace(); } try { if (null != out) out.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 多线程拷贝文件 RandomAccessFile * * @param srcFile 源文件 * @param targetFile 目标文件 */ private static void copyFileMultipleThread(final File srcFile, final File targetFile) { final long srcFileLength = srcFile.length(); int threadNum = (int) (srcFileLength / BIG_FILE_SIZE); if (threadNum > MAX_THREAD_NUM) threadNum = MAX_THREAD_NUM; long residuumFileLength = srcFileLength % threadNum; //每份文件大小 long perFileSize = (srcFileLength - residuumFileLength) / threadNum; //开始位置 long startPosition = 0; //结束位置 long endPosition = perFileSize; for (int i = 0; i < threadNum; i++) { new Thread(new FileCopyWorker(srcFile, targetFile, startPosition, endPosition)).start(); //下一现场读取文件开始位置 startPosition = endPosition + 1; //下一现场读取文件结束位置 endPosition += perFileSize; //最后一个线程读取到文件末 if (i == threadNum - 2) endPosition = srcFileLength; } } private static void makeParentDirs(final File file) throws FileNotFoundException { if (null == file) throw new FileNotFoundException("target file must not be null!"); File parent = file.getParentFile(); if (!parent.exists()) parent.mkdirs(); } private FileCopyUtils() { throw new IllegalAccessError("can not create instance!"); } }
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3200 引用 • 8215 回帖 • 2 关注
  • IO
    8 引用 • 20 回帖
  • Test

    如果你要试验论坛功能,请到 Sandbox 标签下发帖。

    14 引用 • 29 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • zhongmc via iPhone

    不错

    1 回复
  • 其他回帖
  • shinchan via iPhone

    看了代码,应该不存在资源竞争的问题,难道是 RandomAccessFile 并发的问题?

    1 回复
  • 88250

    估计是,你得介绍下思路啊

    1 回复
  • pangwen

    我也没弄清楚到底为啥呢,测试 2g 以上的大文件好多遍,发现单线程更快。。

  • 查看全部回帖

推荐标签 标签

  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 47 关注
  • RemNote
    2 引用 • 16 回帖 • 9 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25296 引用 • 104435 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 761 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 787 关注
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    42 引用 • 130 回帖 • 248 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 6 关注
  • Visio
    1 引用 • 2 回帖 • 3 关注
  • 笔记

    好记性不如烂笔头。

    310 引用 • 794 回帖
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    108 引用 • 295 回帖
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖
  • BAE

    百度应用引擎(Baidu App Engine)提供了 PHP、Java、Python 的执行环境,以及云存储、消息服务、云数据库等全面的云服务。它可以让开发者实现自动地部署和管理应用,并且提供动态扩容和负载均衡的运行环境,让开发者不用考虑高成本的运维工作,只需专注于业务逻辑,大大降低了开发者学习和迁移的成本。

    19 引用 • 75 回帖 • 668 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 573 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 78 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 281 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 8 关注
  • 禅道

    禅道是一款国产的开源项目管理软件,她的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理、计划管理、发布管理、文档管理、事务管理等功能,在一个软件中就可以将软件研发中的需求、任务、bug、用例、计划、发布等要素有序的跟踪管理起来,完整地覆盖了项目管理的核心流程。

    6 引用 • 15 回帖 • 17 关注
  • OnlyOffice
    4 引用 • 22 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 367 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    56 引用 • 85 回帖 • 1 关注
  • Access
    1 引用 • 3 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    89 引用 • 1249 回帖 • 408 关注
  • 叶归
    6 引用 • 17 回帖 • 12 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    181 引用 • 821 回帖
  • Chrome

    Chrome 又称 Google 浏览器,是一个由谷歌公司开发的网页浏览器。该浏览器是基于其他开源软件所编写,包括 WebKit,目标是提升稳定性、速度和安全性,并创造出简单且有效率的使用者界面。

    63 引用 • 289 回帖
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    432 引用 • 1250 回帖 • 598 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    173 引用 • 3849 回帖 • 1 关注