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

本贴最后更新于 2933 天前,其中的信息可能已经时移世异
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 回帖
  • 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

    共勉 😄

请输入回帖内容 ...

推荐标签 标签

  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    199 引用 • 542 回帖
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 77 回帖
  • 招聘

    哪里都缺人,哪里都不缺人。

    188 引用 • 1057 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    5 引用 • 16 回帖 • 3 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 488 关注
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 384 回帖 • 10 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    948 引用 • 1460 回帖 • 1 关注
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    21 引用 • 245 回帖 • 226 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 57 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 191 关注
  • OnlyOffice
    4 引用 • 22 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 116 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 639 关注
  • 尊园地产

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

    1 引用 • 22 回帖 • 788 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 399 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 20 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 35 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 1 关注
  • 爬虫

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

    106 引用 • 275 回帖
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖 • 1 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖 • 3 关注
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖 • 5 关注
  • 外包

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

    26 引用 • 233 回帖 • 4 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖
  • abitmean

    有点意思就行了

    36 关注