Java-文件分块和合并

本文主要介绍Java文件流,读写文件、文件分块与合并

文章目录

  • 前言
  • 代码
    • 文件流读写文件
    • 文件分块和合并
      • 文件分块
      • 文件合并
    • 其他操作
      • 生成文件的MD5值
      • 生成文件名称
      • 校验文件是否为同一个
    • 代码测试

前言

在实际开发中,对文件的操作必不可少,要求对文件流的熟练使用,本文将首先介绍使用文件流读写文件;然后对文件分块合并;其他介绍文件完整性校验,生成名称;最后代码测试运行。

代码

文件流读写文件

package com.ym.learn.test.other;

import org.junit.jupiter.api.Test;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Author: Yangmiao
 * @Date: 2023/5/24 20:35
 * @Desc:
 */
public class IOTest {
    /**
     * 注意文件路径,不加这个前缀,除非将文件放在module根目录下
     */
    private static final String FILE_PREFIX = "src/main/java/com/ym/learn/test/other/";

    @Test
    public void testIO() throws IOException {
        long startTime = System.currentTimeMillis();
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            inputStream = new FileInputStream(FILE_PREFIX+"test.txt");
            // 没有文件时,创建
            File newFile = new File(FILE_PREFIX+"tmp.txt");
            if (!newFile.exists()){
                newFile.createNewFile();
            }
            outputStream = new FileOutputStream(newFile);
            byte[] bytes = new byte[1024*1024];
            int len = 0;
            while ((len = inputStream.read(bytes)) != -1) {
                outputStream.write(bytes,0,len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (outputStream != null){
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
        long costTime = System.currentTimeMillis() - startTime;
        System.out.println("运行时间:"+costTime);
    }

    @Test
    public void testChannel() throws IOException {
        long startTime = System.currentTimeMillis();
        String inputFilePath = FILE_PREFIX+"test.txt";
        String outputFilePath = FILE_PREFIX+"tmp.txt";
        File file = new File(outputFilePath);
        if(!file.exists()){
            file.createNewFile();
        }
        // 创建随机存取文件对象
        RandomAccessFile read = new RandomAccessFile(inputFilePath, "rw");
        RandomAccessFile write = new RandomAccessFile(outputFilePath, "rw");
        // 获取文件通道
        FileChannel readChannel = read.getChannel();
        FileChannel writeChannel = write.getChannel();
        // 使用ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        while (readChannel.read(byteBuffer) > 0){
            byteBuffer.flip();
            writeChannel.write(byteBuffer);
            byteBuffer.clear();
        }
        // 关闭通道
        read.close();
        write.close();

        // time
        long endTime = System.currentTimeMillis();
        System.out.println("时间:"+(endTime-startTime));
    }
}

文件分块和合并

文件分块

/**
     * 文件分块
     * @param src 源文件路径
     * @param dest   文件分块后保存路径
     * @return
     */
    public static boolean chunkFile(String src, String dest) {
        if (StrUtil.isEmpty(src) || StrUtil.isEmpty(dest)){
            return false;
        }
        // 源文件
        File sourceFile = new File(src);
        // 文件分块个数,向上取整
        int chunkNum = (int) Math.ceil(sourceFile.length()*1.0 / FILE_BLOCK_SIZE);
        // 缓冲区
        byte[] bytes = new byte[1024*1024];
        // 文件读入流
        RandomAccessFile read = null;
        try {
            read = new RandomAccessFile(sourceFile,"r");
            for (int i = 0; i < chunkNum; i++) {
                File destFile = new File(dest + "/" + i);
                System.out.println("chunkNum: "+chunkNum+" currentNum: "+i);
                System.out.println("read " + destFile.getAbsolutePath());
                if (!destFile.exists()) {
                    // 创建上级目录
                    destFile.getParentFile().mkdirs();
                    // 创建文件
                    destFile.createNewFile();
                }
                try (RandomAccessFile write = new RandomAccessFile(destFile, "rw")) {
                    int len = -1;
                    while ((len = read.read(bytes)) != -1) {
                        write.write(bytes, 0, len);
                        // 当分块文件达到默认的分块大小后,break
                        if (destFile.length() >= FILE_BLOCK_SIZE) {
                            break;
                        }
                    }
                }
            }
        } catch (FileNotFoundException  e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (read != null){
                try {
                    read.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

文件合并

/**
     * 合并分块文件为一个文件
     * @param src 源分块文件路径
     * @param dest 合并后文件路径
     * @return
     */
    public static boolean mergeFile(String src, String dest)  {
        if (StrUtil.isEmpty(src) || StrUtil.isEmpty(dest)){
            return false;
        }
        // 查看源文件目录下所有的文件
        File[] files = new File(src).listFiles();
        // 转换数组为list,过滤掉某些文件
        List<File> fileList = Arrays.stream(files)
                // 过滤掉某些文件
                .filter(file -> !FILE_IGNORE_EXTENSIONS.contains(file.getName()))
                // 分块文件升序排序
                .sorted((o1, o2) -> Integer.parseInt(o1.getName()) - Integer.parseInt(o2.getName()))
                .collect(Collectors.toList());
        fileList.forEach(it->{
            System.out.println("fileName: "+it.getName());
        });

        RandomAccessFile write = null;
        try {
            write = new RandomAccessFile(dest, "rw");
            byte[] buffer = new byte[1024*1024];
            for (File file : fileList) {
                RandomAccessFile read = new RandomAccessFile(file, "r");
                int len = -1;
                while ((len = read.read(buffer)) != -1) {
                    write.write(buffer,0,len);
                }
                read.close();
            }
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (write != null){
                try {
                    write.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
       return true;
    }

其他操作

生成文件的MD5值

读入文件流,生成32位的唯一MD5值

/**
     * 根据文件路径获取文件的MD5值
     * @param path
     * @return
     */
    public static String getFileMD5(String path) {
        if (CharSequenceUtil.isEmpty(path)){
            return StrUtil.EMPTY;
        }
        try(FileInputStream read = new FileInputStream(path)) {
            return DigestUtils.md5Hex(read);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return StrUtil.EMPTY;
    }

    /**
     * 根据传入的文件得到MD5值
     * @param file
     * @return
     */
    public static String getFileMD5(File file)  {
        if (file == null){
            return StrUtil.EMPTY;
        }
        try(FileInputStream read = new FileInputStream(file)){
            return DigestUtils.md5Hex(read);
        }catch (IOException e) {
            e.printStackTrace();
        }
        return StrUtil.EMPTY;
    }

生成文件名称

如果不传入文件的md5名称,代码自动生成一个fileName

/**
     * 根据当前日期、随机hash值生成文件名称
     * 比如:
     * fileName: 2023/05/28/39ff5139860b4d889bfc9b225813b3aa
     * fileName: 2023/05/28/7c923755032744ffa619839b69a9428d.png
     * fileName: 2023/05/28/fsfsfsfs.jpeg
     * @param fileMd5 文件fileMD5值
     * @param fileExtension 文件扩展名
     * @return
     */
    public static String getDateMD5Name(String fileMd5, String fileExtension){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String format = sdf.format(new Date());
        String fileName = "";
        if (StrUtil.isNotEmpty(fileMd5)){
            fileName = format+"/"+fileMd5;
        }else {
            fileName = format+"/"+UUID.randomUUID().toString().replace("-", "");
        }
        if (StrUtil.isNotEmpty(fileExtension)){
            fileName = fileName+fileExtension;
        }
        System.out.println("fileName: " + fileName);
        return fileName;
    }

校验文件是否为同一个

/**
     * 校验文件是否为同一个
     * @param src
     * @param dest
     * @return
     */
    public static boolean checkFileIsSame(String src, String dest){
        if (StrUtil.isEmpty(src) || StrUtil.isEmpty(dest)){
            return false;
        }
        String srcFileMD5 = getFileMD5(src);
        String srcDestMD5 = getFileMD5(dest);
        if (StrUtil.isEmpty(srcFileMD5) || StrUtil.isEmpty(srcDestMD5)){
            return false;
        }
        if (srcFileMD5.equals(srcDestMD5)){
            return true;
        }
        return false;
    }

代码测试

@Test
public void test(){
    // 测试文件的MD5值
    getDateMD5Name(null,null);
    getDateMD5Name(null,".png");
    getDateMD5Name("fsfsfsfs",".jpeg");

    // 测试分块文件
    String src = "/Users/yangmiao/Downloads/Snipaste-2.8.3-Beta2.dmg";
    String destChunk = "/Users/yangmiao/Downloads/chunkPath/";
    String destMerge = "/Users/yangmiao/Downloads/Snipaste-2.8.3-Beta2_merge.dmg";
    boolean chunkFileRet = chunkFile(src, destChunk);
    Assertions.assertTrue(chunkFileRet);

    boolean mergeFileRet = mergeFile(destChunk, destMerge);
    Assertions.assertTrue(mergeFileRet);

    boolean fileIsSame = checkFileIsSame(src, destMerge);
    System.out.println("fileIsSame: " + fileIsSame);
    Assertions.assertTrue(fileIsSame);
}

你可能感兴趣的:(#,基础知识,java,junit,开发语言)