JAVA——把一批压缩文件中存放的部分数据进行处理(替换)
- 一、需求
- 二、分析
- 三、具体实现
- 1.解压压缩文件
- 2.读取解压后的文件并且按照一定逻辑处理
- 3.把文件压缩存储
- 4.方法的调用
- 5.需要添加的依赖
- 四、执行结果
- 五、用到的工具类
- 六、可以改进的地方
- 1.文件处理完成后,删除临时文件和文件夹会出现删除失败的问题
- 2.调用方法时所有操作(解压-修改数据-压缩-保存)可以分文件夹完成
一、需求
有一批已经压缩存档的数据文件(压缩文件格式为.tar.gz,解压后为.txt文件),现在需要把每个文件中符合需要的字段数据进行更改替换,因为文件量大,需要替换的字段数据有明确共同点(数据在文件每一行中所处同一个位置),因此写个脚本来处理是比较省时的做法。
- 样例数据如图所示:
- 比如说,这个表里存的是用户信息,其中用户名是敏感数据,需要把所有用户名替换成******
二、分析
以上需求可以分解为三个步骤:
1.解压压缩文件
2.读取解压后的文件并且按照一定逻辑处理
3.把文件压缩存储
三、具体实现
1.解压压缩文件
- 解压文件方法如下:
/**
* 批量解压文件夹下的所有.tar.gz文件
*
* @param sourcePath 要解压的文件夹
* @param targetPath 解压到目标路径
* @return
*/
public static DataEntity<Void> batchDecompressTarGzip(String sourcePath, String targetPath) throws IOException {
log.info("{} 开始批量解压文件 ...", sourcePath);
deleteDirAfterNSeconds(new File(targetPath),0);
File dir = new File(sourcePath);
//遍历文件夹,获取文件完整路径
File[] files = dir.listFiles();
assert files != null;
for (File f : files) {
String filePath = sourcePath + File.separator + f.getName();
//把所有文件解压到目标文件夹
deCompressTarGzip(filePath, targetPath + File.separator + dir.getName());
}
log.info("{} 文件批量解压完成。", sourcePath);
return DataUtils.success();
}
/**
* 解压.tar.gz文件
*
* @param sourcePath 要解压的文件路径加文件名
* @param targetPath 解压到目标路径
* @return
* @throws IOException
*/
public static DataEntity<Void> deCompressTarGzip(String sourcePath, String targetPath) throws IOException {
// //解压文件
// Path source = Paths.get("/home/test/output" + TARGZ);
// //解压到哪
// Path target = Paths.get("/home/test2");
//解压文件
Path source = Paths.get(sourcePath);
//解压到哪
Path target = Paths.get(targetPath);
if (Files.notExists(source)) {
return DataUtils.fail("您要解压的文件不存在: " + source.toAbsolutePath());
}
//InputStream输入流,以下四个流将tar.gz读取到内存并操作
//BufferedInputStream缓冲输入流
//GzipCompressorInputStream解压输入流
//TarArchiveInputStream解tar包输入流
try (InputStream fi = Files.newInputStream(source);
BufferedInputStream bi = new BufferedInputStream(fi);
GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {
ArchiveEntry entry;
while ((entry = ti.getNextEntry()) != null) {
//获取解压文件目录,并判断文件是否损坏
DataEntity<Path> res = zipSlipProtect(entry, target);
if (!res.isOk()) {
return DataUtils.fail(res.getMessage());
}
Path newPath = res.getData();
if (entry.isDirectory()) {
//创建解压文件目录
Files.createDirectories(newPath);
} else {
//再次校验解压文件目录是否存在
Path parent = newPath.getParent();
if (parent != null) {
if (Files.notExists(parent)) {
Files.createDirectories(parent);
}
}
// 将解压文件输入到TarArchiveInputStream,输出到磁盘newPath目录
Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING);
}
}
}
return DataUtils.success();
}
//判断压缩文件是否被损坏,并返回该文件的解压目录
private static DataEntity<Path> zipSlipProtect(ArchiveEntry entry, Path targetDir) {
Path targetDirResolved = targetDir.resolve(entry.getName());
Path normalizePath = targetDirResolved.normalize();
if (!normalizePath.startsWith(targetDir)) {
log.error("压缩文件已被损坏: {}", entry.getName());
return DataUtils.fail("压缩文件已被损坏" + entry.getName());
}
return DataUtils.entityData(normalizePath);
}
2.读取解压后的文件并且按照一定逻辑处理
- 读取和替换文件如下:
/**
* 批量读取和替换txt文件:把经纬度数据替换成0
*
* @param sourcePath 存放.txt文件的目录
* @return
*/
public static DataEntity<Void> readAndReplaceTxt(String sourcePath, String targetPath) throws IOException {
log.info("开始批量替换敏感数据");
deleteDirAfterNSeconds(new File(targetPath),0);
File dir = new File(sourcePath);
File fileDir = dir.listFiles()[0];
File[] files = fileDir.listFiles();
//遍历文件
assert files != null;
for (File file : files) {
String newFileName = file.getName();
String newFileDir = targetPath + File.separator + fileDir.getName();
Files.createDirectories(Paths.get(newFileDir));
String newFilePath = newFileDir + File.separator + newFileName;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
//构造一个BufferedReader类来读取文件
String lineTxt = null;
//result用来存储文件内容
// StringBuilder result = new StringBuilder();
//按使用readLine方法,一次读一行
while ((lineTxt = bufferedReader.readLine()) != null) {
//替换
int i = StringUtils.ordinalIndexOf(lineTxt, "\t", 2);
int j = StringUtils.ordinalIndexOf(lineTxt, "\t", 4);
String newContent = lineTxt.replace(lineTxt.substring(i, j), "\t0\t0");//替换
// result.append(newContent);
File newFile = new File(newFilePath);
PrintStream ps = new PrintStream(new FileOutputStream(newFile, true));
ps.println(newContent);// 往.txt文件里写入字符串
}
log.info("文件 {} 中敏感数据替换执行完毕", newFilePath);
} catch (Exception e) {
log.error("读取文件 {} 内容出错", newFilePath);
return DataUtils.fail(e.getMessage());
}
}
log.info("敏感数据批量替换完成。");
return DataUtils.success();
}
3.把文件压缩存储
- 压缩文件如下
/**
* 压缩.txt文件为.tar.gz文件(压缩后文件名不变,仅后缀发生变化)
*
* @param resourceFile 要压缩的文件
* @param targetDir 要存放的路径
* @return
* @throws IOException
*/
public static DataEntity<Void> fileTarGzip(File resourceFile, String targetDir) throws IOException {
//获取输出后的文件名
String oldName = resourceFile.getName();
int i = oldName.indexOf(TXT);
String newName = oldName.substring(0, i) + TARGZ;
String outPath = targetDir + File.separator + newName;
Path path = Paths.get(outPath + TMP);
try (FileOutputStream fileOutputStream = new FileOutputStream(outPath + TMP);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream);
TarOutputStream tarOutputStream = new TarOutputStream(bufferedOutput);
FileInputStream fileInputStream = new FileInputStream(resourceFile);
BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream);
) {
TarEntry entry = new TarEntry(new File(oldName));
entry.setSize(resourceFile.length());
tarOutputStream.putNextEntry(entry);
IOUtils.copy(bufferedInput, tarOutputStream);
tarOutputStream.closeEntry();
} catch (Exception e) {
Files.delete(path);
log.error("文件压缩至 {} 执行异常,嵌套异常!", outPath, e);
}
// 读取打包好的 tar 临时文件,使用 GZIP 方式压缩
try (FileInputStream fin = new FileInputStream(outPath + TMP);
BufferedInputStream bin = new BufferedInputStream(fin);
FileOutputStream fout = new FileOutputStream(outPath);
GZIPOutputStream gout = new GZIPOutputStream(fout);
BufferedOutputStream bout = new BufferedOutputStream(gout);
) {
byte[] cache = new byte[1024];
for (int index = bin.read(cache); index != -1; index = bin.read(cache)) {
bout.write(cache, 0, index);
}
log.info("文件 {} 压缩执行完毕", outPath);
} catch (Exception e) {
log.error("文件压缩至 {} 执行异常,嵌套异常!", outPath, e);
} finally {
Files.delete(path);
}
return DataUtils.success();
}
/**
* 批量压缩.txt文件为.tar.gz文件(压缩后文件名不变,仅后缀发生变化)
*
* @param sourceDir 要压缩的文件存放的目录
* @param targetDir 要存放的路径
* @return
* @throws IOException
*/
public static DataEntity<Void> filesTarGzip(String sourceDir, String targetDir) throws IOException {
log.info("{} 开始批量执行压缩文件...", targetDir);
File dir = new File(sourceDir);
//获取目标文件夹下的所有文件夹
File fileDir = dir.listFiles()[0];
File[] files = fileDir.listFiles();
assert files != null;
for (File f : files) {
fileTarGzip(f, targetDir);
}
log.info("{} 文件批量压缩完成。", targetDir);
return DataUtils.success();
}
4.方法的调用
FileOperateService.java
@Slf4j
@Service
public class FileOperateService {
/**
* 批量处理文件:把压缩文件解压、将解压后的文件经纬度数据替换成0,重新把文件压缩回原来的目录
* @param source 文件夹路径:存放要处理的文件
* @param temp 文件夹路径:任意临时文件夹
* @param temp2 文件夹路径:任意临时文件夹
* @return
* @throws IOException
*/
public DataEntity<Void> operate(String source, String temp, String temp2) throws IOException {
//把source目录下的.tar.gz文件批量解压成.txt文件到临时temp目录下
DataEntity<Void> decompressFiles = FileUpdateUtils.batchDecompressTarGzip(source, temp);
if (decompressFiles.isOk()) {
//把临时temp目录下的.txt文件批量替换掉经纬度数据后,存到临时temp2目录下
DataEntity<File[]> readAndReplaceData = FileUpdateUtils.readAndReplaceTxt(temp, temp2);
//如果经纬度替换成功,就删除临时目录temp
FileUpdateUtils.deleteTempDir(temp);
if (readAndReplaceData.isOk()) {
//把临时temp2目录下的.txt文件压缩成.tar.gz文件,存放到source目录下
DataEntity<Void> compressFiles = FileUpdateUtils.filesTarGzip(temp2, source);
//如果压缩成功,就删除临时目录temp2
FileUpdateUtils.deleteTempDir(temp2);
return compressFiles;
} else {
return DataUtils.fail(readAndReplaceData.getMessage());
}
}
return decompressFiles;
}
}
FileUpdateResource.java
@RestController
@RequestMapping("/api")
public class FileUpdateResource {
private final Logger log = LoggerFactory.getLogger(FileUpdateResource.class);
private final FileOperateService fileOperateService;
public FileUpdateResource(FileOperateService fileOperateService) {
this.fileOperateService = fileOperateService;
}
/**
* 批量处理文件:把压缩文件内的经纬度数据替换成0
* @param source 文件夹路径:存放要处理的文件
* @param temp 文件夹路径:任意临时文件夹
* @param temp2 文件夹路径:任意临时文件夹
* @return
* @throws IOException
*/
@PostMapping("/file/operate")
public DataEntity<Void> operateFile(@RequestParam("source") String source,@RequestParam("temp") String temp,@RequestParam("temp2") String temp2) throws IOException {
log.debug("REST request operate File");
return fileOperateService.operate(source,temp,temp2);
}
}
5.需要添加的依赖
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>0.7</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
四、执行结果
如图所示:
五、用到的工具类
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPOutputStream;
public class FileUpdateUtils {
public static final String TARGZ = ".tar.gz";
private static final String TXT = ".txt";
private static final String TMP = ".tmp";
private static final Logger log = LoggerFactory.getLogger(TarGzUtils.class);
// 文件删除任务的线程池
private static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
/**
* 批量解压文件夹下的所有.tar.gz文件
*
* @param sourcePath 要解压的文件夹
* @param targetPath 解压到目标路径
* @return
*/
public static DataEntity<Void> batchDecompressTarGzip(String sourcePath, String targetPath) throws IOException {
log.info("{} 开始批量解压文件 ...", sourcePath);
deleteDirAfterNSeconds(new File(targetPath),0);
File dir = new File(sourcePath);
//遍历文件夹,获取文件完整路径
File[] files = dir.listFiles();
assert files != null;
for (File f : files) {
String filePath = sourcePath + File.separator + f.getName();
//把所有文件解压到目标文件夹
deCompressTarGzip(filePath, targetPath + File.separator + dir.getName());
}
log.info("{} 文件批量解压完成。", sourcePath);
return DataUtils.success();
}
/**
* 解压.tar.gz文件
*
* @param sourcePath 要解压的文件路径加文件名
* @param targetPath 解压到目标路径
* @return
* @throws IOException
*/
public static DataEntity<Void> deCompressTarGzip(String sourcePath, String targetPath) throws IOException {
// //解压文件
// Path source = Paths.get("/home/test/output" + TARGZ);
// //解压到哪
// Path target = Paths.get("/home/test2");
//解压文件
Path source = Paths.get(sourcePath);
//解压到哪
Path target = Paths.get(targetPath);
if (Files.notExists(source)) {
return DataUtils.fail("您要解压的文件不存在: " + source.toAbsolutePath());
}
//InputStream输入流,以下四个流将tar.gz读取到内存并操作
//BufferedInputStream缓冲输入流
//GzipCompressorInputStream解压输入流
//TarArchiveInputStream解tar包输入流
try (InputStream fi = Files.newInputStream(source);
BufferedInputStream bi = new BufferedInputStream(fi);
GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) {
ArchiveEntry entry;
while ((entry = ti.getNextEntry()) != null) {
//获取解压文件目录,并判断文件是否损坏
DataEntity<Path> res = zipSlipProtect(entry, target);
if (!res.isOk()) {
return DataUtils.fail(res.getMessage());
}
Path newPath = res.getData();
if (entry.isDirectory()) {
//创建解压文件目录
Files.createDirectories(newPath);
} else {
//再次校验解压文件目录是否存在
Path parent = newPath.getParent();
if (parent != null) {
if (Files.notExists(parent)) {
Files.createDirectories(parent);
}
}
// 将解压文件输入到TarArchiveInputStream,输出到磁盘newPath目录
Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING);
}
}
}
return DataUtils.success();
}
/**
* 批量读取和替换txt文件:把经纬度数据替换成0
*
* @param sourcePath 存放.txt文件的目录
* @return
*/
public static DataEntity<Void> readAndReplaceTxt(String sourcePath, String targetPath) throws IOException {
log.info("开始批量替换敏感数据");
deleteDirAfterNSeconds(new File(targetPath),0);
File dir = new File(sourcePath);
File fileDir = dir.listFiles()[0];
File[] files = fileDir.listFiles();
//遍历文件
assert files != null;
for (File file : files) {
String newFileName = file.getName();
String newFileDir = targetPath + File.separator + fileDir.getName();
Files.createDirectories(Paths.get(newFileDir));
String newFilePath = newFileDir + File.separator + newFileName;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
//构造一个BufferedReader类来读取文件
String lineTxt = null;
//result用来存储文件内容
// StringBuilder result = new StringBuilder();
//按使用readLine方法,一次读一行
while ((lineTxt = bufferedReader.readLine()) != null) {
//替换
int i = StringUtils.ordinalIndexOf(lineTxt, "\t", 2);
int j = StringUtils.ordinalIndexOf(lineTxt, "\t", 4);
String newContent = lineTxt.replace(lineTxt.substring(i, j), "\t0\t0");//替换
// result.append(newContent);
File newFile = new File(newFilePath);
PrintStream ps = new PrintStream(new FileOutputStream(newFile, true));
ps.println(newContent);// 往.txt文件里写入字符串
}
log.info("文件 {} 中敏感数据替换执行完毕", newFilePath);
} catch (Exception e) {
log.error("读取文件 {} 内容出错", newFilePath);
return DataUtils.fail(e.getMessage());
}
}
log.info("敏感数据批量替换完成。");
return DataUtils.success();
}
//判断压缩文件是否被损坏,并返回该文件的解压目录
private static DataEntity<Path> zipSlipProtect(ArchiveEntry entry, Path targetDir) {
Path targetDirResolved = targetDir.resolve(entry.getName());
Path normalizePath = targetDirResolved.normalize();
if (!normalizePath.startsWith(targetDir)) {
log.error("压缩文件已被损坏: {}", entry.getName());
return DataUtils.fail("压缩文件已被损坏" + entry.getName());
}
return DataUtils.entityData(normalizePath);
}
/**
* 压缩.txt文件为.tar.gz文件(压缩后文件名不变,仅后缀发生变化)
*
* @param resourceFile 要压缩的文件
* @param targetDir 要存放的路径
* @return
* @throws IOException
*/
public static DataEntity<Void> fileTarGzip(File resourceFile, String targetDir) throws IOException {
//获取输出后的文件名
String oldName = resourceFile.getName();
int i = oldName.indexOf(TXT);
String newName = oldName.substring(0, i) + TARGZ;
String outPath = targetDir + File.separator + newName;
Path path = Paths.get(outPath + TMP);
try (FileOutputStream fileOutputStream = new FileOutputStream(outPath + TMP);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream);
TarOutputStream tarOutputStream = new TarOutputStream(bufferedOutput);
FileInputStream fileInputStream = new FileInputStream(resourceFile);
BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream);
) {
TarEntry entry = new TarEntry(new File(oldName));
entry.setSize(resourceFile.length());
tarOutputStream.putNextEntry(entry);
IOUtils.copy(bufferedInput, tarOutputStream);
tarOutputStream.closeEntry();
} catch (Exception e) {
Files.delete(path);
log.error("文件压缩至 {} 执行异常,嵌套异常!", outPath, e);
}
// 读取打包好的 tar 临时文件,使用 GZIP 方式压缩
try (FileInputStream fin = new FileInputStream(outPath + TMP);
BufferedInputStream bin = new BufferedInputStream(fin);
FileOutputStream fout = new FileOutputStream(outPath);
GZIPOutputStream gout = new GZIPOutputStream(fout);
BufferedOutputStream bout = new BufferedOutputStream(gout);
) {
byte[] cache = new byte[1024];
for (int index = bin.read(cache); index != -1; index = bin.read(cache)) {
bout.write(cache, 0, index);
}
log.info("文件 {} 压缩执行完毕", outPath);
} catch (Exception e) {
log.error("文件压缩至 {} 执行异常,嵌套异常!", outPath, e);
} finally {
Files.delete(path);
}
return DataUtils.success();
}
/**
* 批量压缩.txt文件为.tar.gz文件(压缩后文件名不变,仅后缀发生变化)
*
* @param sourceDir 要压缩的文件存放的目录
* @param targetDir 要存放的路径
* @return
* @throws IOException
*/
public static DataEntity<Void> filesTarGzip(String sourceDir, String targetDir) throws IOException {
log.info("{} 开始批量执行压缩文件...", targetDir);
File dir = new File(sourceDir);
//获取目标文件夹下的所有文件夹
File fileDir = dir.listFiles()[0];
File[] files = fileDir.listFiles();
assert files != null;
for (File f : files) {
fileTarGzip(f, targetDir);
}
log.info("{} 文件批量压缩完成。", targetDir);
return DataUtils.success();
}
/**
* 删除一个文件夹和里面的文件
*
* @param dirPath 文件夹路径
* @return
*/
public static DataEntity<Void> deleteTempDir(String dirPath) {
System.gc();
File file = new File(dirPath);
deleteFile(file);
// if (deleteFile(file).isOk()) {
// log.info(dirPath + "目录下文件删除成功!");
// }
return DataUtils.success();
}
public static DataEntity<Void> deleteFile(File file) {
//判断文件不为null或文件目录存在
if (file == null || !file.exists()) {
return DataUtils.fail("文件删除失败,请检查文件是否存在以及文件路径是否正确");
}
//获取目录下子文件
File[] files = file.listFiles();
//遍历该目录下的文件对象
assert files != null;
for (File f : files) {
//判断子目录是否存在子目录,如果是文件则删除
if (f.isDirectory()) {
//递归删除目录下的文件
deleteFile(f);
} else {
//文件删除
f.delete();
}
}
//文件夹删除
file.delete();
return DataUtils.success();
}
/**
* 延迟若干秒后执行删除操作
* @param file
* @param seconds
*/
public static void deleteDirAfterNSeconds(File file, int seconds) {
scheduledThreadPool.schedule(new Runnable() {
public void run() {
try {
if (file.exists()) {
// 两种删除方式都用上
deleteDir(file);
deleteDirByCmd(file);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}, seconds, TimeUnit.SECONDS);
}
/**
* 通过调用系统命令删除一个文件夹及下面的所有文件
*/
public static void deleteDirByCmd(File file) {
// 文件不存在直接返回
if (null == file || !file.exists()) {
return;
}
// 文件存在时执行删除操作
Runtime rt = Runtime.getRuntime();
try {
String cmd = null;
if (file.isFile()) {
cmd = "cmd.exe /c del /q/a/f/s " + file.getAbsolutePath();
} else {
cmd = "cmd.exe /c rd /s/q " + file.getAbsolutePath();
}
rt.exec(cmd);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 递归删除目录下的所有文件及子目录下所有文件
* @param dir 将要删除的文件目录|文件
*/
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
}
六、可以改进的地方
1.文件处理完成后,删除临时文件和文件夹会出现删除失败的问题
问题背景:
通过IO流操作过文件后,最后想删除过程中产生的临时文件,有部分文件未被删除,也不报错。
已经检查过所有的流都关闭了。
问题原因:
临时文件对象在java虚拟机(jvm)中还未被解除引用,虽然看似没有变量指向这个临时文件对象了,但还没来得急被垃圾收集器自动回收解除引用。
解决:
方案一:执行删除操作前手动把垃圾回收一下
/**
* 删除一个文件夹和里面的文件
*
* @param dirPath 文件夹路径
* @return
*/
public static DataEntity<Void> deleteTempDir(String dirPath) {
System.gc();
File file = new File(dirPath);
deleteFile(file);
if (deleteFile(file).isOk()) {
log.info(dirPath + "目录下文件删除成功!");
}
return DataUtils.success();
}
public static DataEntity<Void> deleteFile(File file) {
//判断文件不为null或文件目录存在
if (file == null || !file.exists()) {
return DataUtils.fail("文件删除失败,请检查文件是否存在以及文件路径是否正确");
}
//获取目录下子文件
File[] files = file.listFiles();
//遍历该目录下的文件对象
assert files != null;
for (File f : files) {
//判断子目录是否存在子目录,如果是文件则删除
if (f.isDirectory()) {
//递归删除目录下的文件
deleteFile(f);
} else {
//文件删除
f.delete();
}
}
//文件夹删除
file.delete();
return DataUtils.success();
}
方案二:延时若干秒后对文件进行删除
import java.io.File;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 文件删除工具类
*/
public class FileDeleteUtil {
// 文件删除任务的线程池
private static ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
/**
* 延迟若干秒后执行删除操作
* @param file
* @param seconds
*/
public static void deleteDirAfterNSeconds(File file, int seconds) {
scheduledThreadPool.schedule(new Runnable() {
public void run() {
try {
if (file.exists()) {
// 两种删除方式都用上
deleteDir(file);
deleteDirByCmd(file);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}, seconds, TimeUnit.SECONDS);
}
/**
* 通过调用系统命令删除一个文件夹及下面的所有文件
*/
public static void deleteDirByCmd(File file) {
// 文件不存在直接返回
if (null == file || !file.exists()) {
return;
}
// 文件存在时执行删除操作
Runtime rt = Runtime.getRuntime();
try {
String cmd = null;
if (file.isFile()) {
cmd = "cmd.exe /c del /q/a/f/s " + file.getAbsolutePath();
} else {
cmd = "cmd.exe /c rd /s/q " + file.getAbsolutePath();
}
rt.exec(cmd);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 递归删除目录下的所有文件及子目录下所有文件
* @param dir 将要删除的文件目录|文件
*/
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
}
2.调用方法时所有操作(解压-修改数据-压缩-保存)可以分文件夹完成
全量数据都一次性操作完成的话,在数据量大的情况下,就会非常占用内存空间,可以采用所有操作分目录进行(解压-修改数据-压缩-保存)的方式来,修改调用代码如下:
(同时把方法调用的参数写到了配置文件里,因为本操作只需要执行一次,所以不需要写成接口。)
/**
* 批量处理文件:把压缩文件解压、将解压后的文件经纬度数据替换成0,重新把文件压缩回原来的目录
* @return
* @throws IOException
*/
public DataEntity<Void> operate() throws IOException {
String source = conf.getSource();
String temp = conf.getTemp();
String temp2 = conf.getTemp2();
Integer start = conf.getStart();
Integer end = conf.getEnd();
File dirs = new File(source);
for (File dir : dirs.listFiles()) {
String dirName = dir.getName();
Integer date = getDate(dirName);
//遍历日期文件夹,处理日期范围内的文件夹内的压缩文件
if (start <= date && date <= end) {
//把source\日期目录下的.tar.gz文件批量解压成.txt文件到临时temp目录下
DataEntity<Void> decompressFiles = FileUpdateUtils.batchDecompressTarGzip(source+File.separator+dirName, temp);
if (decompressFiles.isOk()) {
//把临时temp目录下的.txt文件批量替换掉经纬度数据后,存到临时temp2目录下
DataEntity<Void> readAndReplaceData = FileUpdateUtils.readAndReplaceTxt(temp, temp2);
if (readAndReplaceData.isOk()) {
//把临时temp2目录下的.txt文件压缩成.tar.gz文件,存放到source目录下
DataEntity<Void> compressFiles = FileUpdateUtils.filesTarGzip(temp2, source+File.separator+dirName);
}
}
//删除临时目录和其中的临时文件
FileUpdateUtils.deleteTempDir(temp);
FileUpdateUtils.deleteTempDir(temp2);
log.info("{} 敏感数据已经完成替换。", date);
}
}
//再次删除临时目录和其中的临时文件
FileUpdateUtils.deleteDirAfterNSeconds(new File(temp),3);
FileUpdateUtils.deleteDirAfterNSeconds(new File(temp2),3);
return DataUtils.success();
}
private Integer getDate(String dirName) {
return Integer.parseInt(dirName.substring(0, 8));
}