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

本贴最后更新于 2893 天前,其中的信息可能已经时移世异
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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3194 引用 • 8214 回帖
  • IO
    8 引用 • 20 回帖
  • Test

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

    14 引用 • 29 回帖 • 1 关注

相关帖子

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • pangwen

    @88250 直接贴代码是不是都没人愿意看的啊 😢

    1 回复
  • 88250

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

    1 回复
  • pangwen

    表达能力实在捉鸡。。 然后 markdown 不会用,代码贴的很凌乱。

    1 回复
  • 88250
    1 回复
  • pangwen

    我看了教程,但是贴代码的时候还是失败了。。 然后无意间发现双 TAB 可以显示代码,之后就这样贴出来了 😢

  • shinchan via iPhone

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

    1 回复
  • zhongmc via iPhone

    不错

    1 回复
  • pangwen

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

  • pangwen

    共勉 😄

请输入回帖内容 ...

推荐标签 标签

  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    556 引用 • 674 回帖
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    36 引用 • 155 回帖 • 1 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 76 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    28 引用 • 197 回帖 • 25 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 62 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 262 关注
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    54 引用 • 37 回帖
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 175 关注
  • 又拍云

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

    20 引用 • 37 回帖 • 570 关注
  • 游戏

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

    180 引用 • 821 回帖
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 85 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 6 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 1 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 1 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 528 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 701 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 638 关注
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    20 引用 • 23 回帖 • 737 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    116 引用 • 54 回帖 • 5 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    31 引用 • 96 回帖
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 500 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 650 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 651 关注
  • WebComponents

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

    1 引用 • 8 关注