背景

   当有时候一个文件夹下有几万个几十万个文件时,我们的桌面终端打开这个文件夹可能会卡。或者将文件进行批量上传时,如果是在文件夹下全选,那么基本上浏览器就卡死了,当然也不能这样子操作滴~

   题主最近就遇到这样一个问题,批量上传文件,有几万个,担心全选会搞崩浏览器或者cmd终端,于是打算将数据分组,分批次上传,减少风险压力。可能有的同学会说,那简单嘛,直接ctrl C+V完事儿,但是人这个眼睛呐,越集中注意力看一个字,就越不觉得它像个字,所以难免会出错的,而且拖动也会很卡。

作为一个搞电脑的工程师(程序猿),能用电脑解决的,怎么能浪费体力呢[滑稽]

参考步骤

   其实要实现这么一个东西,很简单的,二话不多说,直接一个for循环搞定 欧耶!但是呀,那个速度呀,难以忍受,如果分组这个文件还需要去做一些额外的操作,那岂不是更慢,说到这,想到以前读书学习大数据的时候,分词计算map-reduce那每次一跑就是一个小时过去了,所以,光写出来不得行,还得优化。而且分组的时候有一些注意点要注意。

   题主的大致步骤如下:

  1. 打开文件夹,遍历文件;
  2. 启用线程池,多线程跑批任务,加快速度;
  3. 计数文件夹中文件个数,达到指定数量,建立下一个文件夹;
  4. 使用新的文件夹继续移动或复制文件,操作过程中进行重命名;重复3,4步骤
  5. 操作完毕,等待线程池任务处理完毕,销毁。

代码实现

   说了那么多,还是直接上代码吧:)


import java.io.File;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.*; public class TestReduceFile { /**
* 文件计数
*/
private static volatile int currentFileNum = 0; private static final String initFilePathName = "/Users/anhaoo/test/reduceFile/reduce"; private static volatile String currentFilePathName; public static void main(String[] args) {
groupFile("/User/anhaoo/test/big_pdf");
} /**
* 将文件分组:分成一个文件夹多少个文件这种
* @param oldFilePath
*/
private static void groupFile(String oldFilePath) {
File file = new File(oldFilePath);
File[] fileList = file.listFiles();
// 线程池批处理:链表阻塞队列
ExecutorService executor = Executors.newFixedThreadPool(80);
if (Objects.nonNull(fileList) && fileList.length > 0) {
// System.out.println(fileList.length);
Arrays.stream(fileList).forEach(item -> {
// 线程池提交任务处理
if (!item.isDirectory()) {
executor.execute(() -> groupFileSub(item));
}
});
}
// shutdown 等待任务全部执行完毕 销毁
executor.shutdown();
} /**
* 分组文件,每满n个文件生成下一个文件夹,然后将后续遍历的文件移动到下一个文件夹中
* @param oldFile
*/
private static synchronized void groupFileSub(File oldFile) {
// 判断是否需要新生成文件夹,一个文件夹下放700个
if (currentFileNum % 700 == 0) {
// reduce0,reduce1,reduce2......
String newFileFolder = initFilePathName.concat(String.valueOf(currentFileNum/700));
// 将新的文件夹名赋值给共享变量
currentFilePathName = newFileFolder;
}
File aimFilePath = new File(currentFilePathName);
if (!aimFilePath.exists()) {
aimFilePath.mkdirs();
}
try {
// 移动文件时顺便重命名文件
String oldFileName = oldFile.getName();
String[] fileNameArr = oldFileName.split("_");
// 加下面这个if的原因 是因为mac电脑下有一个隐藏的.DS_Store文件,它按我的规则重命名时会影响我的操作
// 所以判断一下,不然我这里会抛越界异常:)
if (fileNameArr.length < 3) {
return;
}
String uuid = fileNameArr[2];
String newFileName = "/pdfFile_".concat(uuid);
File aimFile = new File(aimFilePath + File.separator + newFileName);
currentFileNum++;
oldFile.renameTo(aimFile);
} catch (Exception e) {
e.printStackTrace();
}
}
}

   代码就如上了,效果如图所示:



701 是因为有一个隐藏文件了哈!

注意事项

   有几个点需要注意一下:上面程序中使用了volatile和synchronized,以及线程池等工具,

  • 使用线程池,是为了多个线程一起处理,加快效率;
  • 使用volatile修饰了两个变量,因为currentFileNum会实时变化,currentFilePathName文件夹也会在执行过程中发生变化

   可能有的同学会有疑惑,既然使用了volatile关键保证了多线程变量的可见性,那为什么还要使用synchronize开持锁同步呢?哈哈哈,刚开始我也是这么认为的,没有使用锁,直接跑,但是每次跑完后每个文件夹的数量不仅不相等而且数量还不一致,不止700个多,后来仔细一想,volatile虽然保持了变量的可见性,但是当多个线程拿到这个变量是将变量副本拷贝到自己的栈内存中,只能保证在获取变量的时候是最新的,但是CPU指令的执行是哪个线程抢到了就去执行,所以可能刚好那个时候其他线程又将变量修改了,因为计数变量currentFileNum在不停地自增,导致线程不安全,不符合我们的预期效果,这个也再一次证明了一个结论:

volatile只是保证了可见性,但是线程变量的安全它无法保证;

所以在这个方法上加了一个锁,保证线程的安全性;

   上述就是本文想分享的东西了,如果有更好的方法或者文章中有不足之处欢迎大家指出,共同进步才是我们的宗旨!

怎样将大批量文件进行循环分组(reduce)?的更多相关文章

  1. Python第五天 文件访问 for循环访问文件 while循环访问文件 字符串的startswith函数和split函数 linecache模块

    Python第五天   文件访问    for循环访问文件    while循环访问文件   字符串的startswith函数和split函数  linecache模块 目录 Pycharm使用技巧( ...

  2. Linux rm删除大批量文件

    在使用rm删除大批量文件时,有可能会遭遇"参数列太长"(Argument list too long)的问题.如下所示 [oracle@DB-Server bdump]$ rm - ...

  3. Linux rm删除大批量文件遇到 Argument list too long

    在使用rm删除大批量文件时,有可能会遭遇“参数列太长”(Argument list too long)的问题.如下所示   [oracle@DB-Server bdump]$ rm -v epps_q ...

  4. VBS文件无限循环解决办法

    VBS文件无限循环解决办法,也就相当于编程中的停止运行指令. 那么如何关掉VBS文件呢?当然关机后会自动关掉,还有另外一种方法就是,在"任务管理器"中找到进程"WScri ...

  5. 读取JSON文件并 排序,分组,

    读取.json文件 public string GetFileJson(string filepath) { string json = string.Empty; using (FileStream ...

  6. php使用PHPexcel类读取excel文件(循环读取每个单元格的数据)

    error_reporting(E_ALL); date_default_timezone_set('Asia/ShangHai'); include_once('Classes/PHPExcel/I ...

  7. JavaScript的map循环、forEach循环、filter循环、reduce循环、reduceRight循环

    1.map循环 let arr=[1,2,3,4]; arr.map(function(value,key,arr){ //值,索引,数组(默认为选定数组) return item; //如果没有re ...

  8. python 文件单行循环读取的坑(一个程序中,文件默认只能按行循环读取一次,即使写到另一个循环里,它也只读取一次)

    本来写了一个程序,想获取a文件中有,但是b文件中没有的行: 想到的方法是:1.一行一行提取a文件中数据,然后用a文件中的每一行与b文件中的每一行比较, 2.如果找到相同行就继续查找a中的下一行,如果找 ...

  9. AIX7.1删除大批量文件(百万级、千万级)

    假设/data/test目录下含有数百万上千万的文件需要删除,可以选择的方式如下: 1.如果文件名不包含空白符.引号等特殊字符,则可以使用如下命令: find /data/test -type f | ...

随机推荐

  1. hdu2639 Bone Collector II

    Problem Description The title of this problem is familiar,isn't it?yeah,if you had took part in the ...

  2. Jenkins 持续集成测试工具

    一.Jenkins(hudson)流程 创建job 执行job 通知机制 二.两种执行策略 定时执行:每隔一段时间执行一下(适合UI和接口测试的执行) 监控代码库执行:单元测试的执行模式(适合单元测试 ...

  3. 国产网络测试仪MiniSMB - 如何3秒内创建出16,000条源/目标MAC地址号递增流

    国产网络测试仪MiniSMB(www.minismb.com)是复刻smartbits的IP网络性能测试工具,是一款专门用于测试智能路由器,网络交换机的性能和稳定性的软硬件相结合的工具.可以通过此以太 ...

  4. 牛客网多校第5场 H subseq 【树状数组+离散化】

    题目:戳这里 学习博客:戳这里 题意:给n个数为a1~an,找到字典序第k小的序列,输出该序列所有数所在位置. 解题思路:先把所有序列预处理出来,方法是设一个数组为dp,dp[i]表示以i为开头的序列 ...

  5. Sublime text 3 中 Package Control安装

    安装前 ctrl+shift+p  在命令板中输入PC,如下图表示没安装: 使用ctrl+~调出sublime软件的控制台命令窗口:粘贴运行 import urllib.request,os,hash ...

  6. HDU 3341 Lost's revenge (AC自动机 + DP + 变进制/hash)题解

    题意:给你些分数串,给你一个主串,主串每出现一个分数串加一分,要你重新排列主串,最多几分 思路:显然这里开$40^4$去状压内存不够.但是我们自己想想会发现根本不用开那么大,因为很多状态是废状压,不是 ...

  7. Go string 一清二楚

    前言 字符串(string) 作为 go 语言的基本数据类型,在开发中必不可少,我们务必深入学习一下,做到一清二楚. 本文假设读者已经知道切片(slice)的使用,如不了解,可阅读 Go 切片 基本知 ...

  8. js code review

    js code review https://codereview.stackexchange.com/ refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只 ...

  9. ESLint & vue

    ESLint & vue { "name": "app", "version": "1.0.1", " ...

  10. NAIO & Node.js All In One

    NAIO & Node.js All In One Node.js Tutorials https://nodejs.org/en/docs/ https://nodejs.org/en/do ...