JAVA——把一批压缩文件中存放的部分数据进行处理(替换)

Posted 叶不修233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA——把一批压缩文件中存放的部分数据进行处理(替换)相关的知识,希望对你有一定的参考价值。

JAVA——把一批压缩文件中存放的部分数据进行处理(替换)

一、需求

有一批已经压缩存档的数据文件(压缩文件格式为.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 
        File file = new File(sourcePath);
        if (!file.isDirectory()) 
            return DataUtils.fail("这不是一个文件夹: " + sourcePath);
        
        //获取目标文件夹下的所有文件
        File[] files = file.listFiles();
        if (files == null) 
            return DataUtils.fail("该文件夹下没有文件: " + sourcePath);
        

        //遍历文件,获取文件完整路径
        for (File f : files) 
            String filePath = sourcePath + "\\\\" + f.getName();
            //把所有文件解压到目标文件夹
            deCompressTarGzip(filePath, targetPath);

        
        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<File[]> readAndReplaceTxt(String sourcePath, String targetPath) throws IOException 
        File fileDir = new File(sourcePath);
        File[] files = fileDir.listFiles();
        if (files == null) 
            return DataUtils.fail("该文件夹下没有文件: " + sourcePath);
        
        //遍历文件
        for (File file : files) 
            String newFileName = file.getName();
            String newFilePath = targetPath + File.separator + newFileName;
            Files.deleteIfExists(Paths.get(newFilePath));
            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", 1);
                    int j = StringUtils.ordinalIndexOf(lineTxt, "\\t", 2);
                    String newContent = lineTxt.replace(lineTxt.substring(i, j), "\\t******");//替换
                    result.append(newContent);
                    File newFile = new File(newFilePath);
                    PrintStream ps = new PrintStream(new FileOutputStream(newFile, true));
                    ps.println(newContent);// 往.txt文件里写入字符串
                
             catch (Exception e) 
                log.error("读取文件内容出错");
                return DataUtils.fail(e.getMessage());
             finally 
                //删除temp文件夹里的临时文件
                Files.delete(Paths.get(sourcePath + File.separator + newFileName));
            
        
        return DataUtils.entityData(files);
    

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 
        File file = new File(sourceDir);
        if (!file.isDirectory()) 
            return DataUtils.fail("这不是一个文件夹: " + sourceDir);
        
        //获取目标文件夹下的所有文件
        File[] files = file.listFiles();
        if (files == null) 
            return DataUtils.fail("该文件夹下没有文件: " + sourceDir);
        

        for (File f : files) 
            fileTarGzip(f, 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>
以上是关于JAVA——把一批压缩文件中存放的部分数据进行处理(替换)的主要内容,如果未能解决你的问题,请参考以下文章

c 文件

将.dat文件导入数据库

将一批数据以二进制形式存放在磁盘文件中

java上传图片到数据库,涉及压缩文件zip/rar上传等

胖瘦客户端区别,SQL Server文件介绍,MySQL数据文件介绍及存放位置

前端-杂文-数据压缩&模块化开发