Fork me on GitHub

工具(1)提供自编文件工具类

额,突然发现有点鸡肋了,apache.common.io 提供FileUtis很好用。。。。。

提供文件工具类,方便以后用到的时候用。有不正之处还请指出。

package com.example.demo.utils;

import com.alibaba.fastjson.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Scanner;

/**
 * 文件工具类
 */
public class CommonFileUtils {

    private static final Logger logger = LoggerFactory.getLogger(CommonFileUtils.class);

    private CommonFileUtils() {
        throw new AssertionError();
    }

    /**
     * 根据路径创建文件,如果路径文件夹不存在,就创建
     *
     * @param filePath
     * @return
     */
    public static File createFileAbsolute(String filePath) throws IOException {
        File file = new File(filePath);
        File fileParent = file.getParentFile();

        if (!fileParent.exists()) {
            fileParent.mkdirs();
        }
        file.createNewFile();
        return file;
    }

    /**
     * 传统写法,JDK1.6
     *
     * @param dataStr
     * @param filePath
     * @return
     */
    public static long randomWrite2FileTradition(String dataStr, String filePath) {
        long fileSize = 0L;
        RandomAccessFile raf = null;
        FileChannel fchannel = null;
        try {
            raf = new RandomAccessFile(createFileAbsolute(filePath), "rw");
            fchannel = raf.getChannel();

            ByteBuffer buf = ByteBuffer.allocate(1024);

            buf.clear();
            buf.put(dataStr.getBytes());
            buf.flip();

            while (buf.hasRemaining()) {
                fchannel.write(buf);
            }

            fileSize = fchannel.size();

        } catch (FileNotFoundException e) {
            logger.error("file not found", e);
        } catch (IOException e) {
            logger.error("IO exception", e);
        } finally {
            IOUtils.close(fchannel);
            IOUtils.close(raf);
        }
        return fileSize;
    }

    /**
     * >=JDK1.7 关闭资源语法糖
     *
     * @param dataStr
     * @param filePath
     * @param isAppendEnd 是否接着文件末尾添加
     * @return
     */
    public static long randomWrite2File(String dataStr, String filePath, boolean isAppendEnd, int bufferSize) {
        long fileSize = 0L;
        try (
                RandomAccessFile raf = new RandomAccessFile(createFileAbsolute(filePath), "rw");
                FileChannel fchannel = raf.getChannel()
        ) {
            ByteBuffer buf = ByteBuffer.allocate(bufferSize);

            buf.put(dataStr.getBytes());

            //limit = position,position=0
            buf.flip();

            if (isAppendEnd) {
                //将文件记录指针定位到pos的位置
                raf.seek(raf.length());
            }

            while (buf.hasRemaining()) {
                fchannel.write(buf);
            }

            fileSize = fchannel.size();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return fileSize;
    }

    /**
     * 读文件,限制:超过 buffSize 字节中文文件,由于ByteBuffer : buffSize,导致中文乱码
     *
     * @param filePath
     * @param piont
     * @param charactSet
     * @return
     */
    public static String randomReadFile(String filePath, int piont, int buffSize, String charactSet) {
        StringBuffer buffer = new StringBuffer();

        // 创建字符集
        Charset charset = Charset.forName(charactSet);

        try (RandomAccessFile raf = new RandomAccessFile(filePath, "r");
             FileChannel fchannel = raf.getChannel()
        ) {
            ByteBuffer buf = ByteBuffer.allocate(buffSize);
            //移动文件指针位置
            raf.seek(piont);

            while (fchannel.read(buf) != -1) {
                // flip方法在读缓冲区字节操作之前调用。   
                buf.flip();

                // 使用Charset.decode方法将字节转换为字符串   
                buffer.append(charset.decode(buf));

                // 清空缓冲   
                buf.clear();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return buffer.toString();
    }

    /**
     * 行读取
     *
     * @param filePath
     * @param charactSet
     * @return
     */
    public static String scannerReadFile(String filePath, String charactSet) {

        LocalDateTime startTime = LocalDateTime.now();

        StringBuffer buffer = new StringBuffer();
        try (FileInputStream inputStream = new FileInputStream(filePath);
             Scanner sc = new Scanner(inputStream, charactSet)
        ) {
            while (sc.hasNextLine()) {
                buffer.append(sc.nextLine()).append("\n");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Long timeConsuming = Duration.between(startTime, LocalDateTime.now()).toMillis();
        logger.info("耗时=" + timeConsuming / 1000 + "s");

        return buffer.toString();
    }

    /**
     * 获取文件属性
     *
     * @param filePath
     * @return
     */
    public static CommonFile getCommonFile(String filePath) {
        File file = new File(filePath);
        CommonFile commonFile = null;
        if (null != file) {
            commonFile = new CommonFile(file.getName(), file.length());
            commonFile.setParentPath(file.getParentFile().getPath());

        } else {
            throw new NullPointerException("File not found");
        }
        return commonFile;
    }

    /**
     * 文件时间戳+number
     *
     * @param number
     * @return
     */
    private static String createFileNameTimeStame(int number) {
        return LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE) + "_" + number;
    }

    /**
     * 拷贝文件
     *
     * @param srcFilePath
     */
    public static long copyFile(String srcFilePath) {
        return copyFile(srcFilePath, 0L, "_bak");
    }

    /**
     * 拷贝文件
     *
     * @param srcFilePath
     */
    public static long copyFile(String srcFilePath, long position, String noteStr) {
        return copyFile(srcFilePath, position, Long.MAX_VALUE, noteStr);
    }

    /**
     * 拷贝文件
     * @param srcFilePath
     * @param position
     * @param end
     * @param noteStr 文件名标识 eg:test20190422_{noteStr}.text
     * @return
     */
    public static long copyFile(String srcFilePath, long position, long end, String noteStr) {
        logger.info("拷贝文件开始.......");
        long targetFileSize = 0L;

        LocalDateTime startTime = LocalDateTime.now();
        String timesStr = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
        String targetFilePath = getTargetFilePath(srcFilePath, timesStr + noteStr);

        try (RandomAccessFile raf = new RandomAccessFile(srcFilePath, "r");
             RandomAccessFile waf = new RandomAccessFile(createFileAbsolute(targetFilePath), "rw");
             FileChannel inFile = raf.getChannel();
             FileChannel outFile = waf.getChannel();
        ) {
            int capacity = 1024 * 10;
            ByteBuffer buf = ByteBuffer.allocate(capacity);

            //起始位
            raf.seek(position);

            while (inFile.read(buf) != -1) {
                // flip方法在读缓冲区字节操作之前调用。   
                buf.flip();

                int conL = (int) (outFile.size() - (end - position));
                if (conL < 0L) {
                    if (conL + capacity >= 0) {
                        //因为中文字符占多个字节,这样会造成buf难免临界,将某个中文给分割了,导致乱码,所以最后一次,定位换行符位置
                        if (buf.hasArray()) {
                            byte[] lastByteArr = getArrToLastLineBreakChar(buf.array());
                            ByteBuffer lastBuf = ByteBuffer.wrap(lastByteArr);
                            outFile.write(lastBuf);
                            targetFileSize = outFile.size();
                            break;
                        }
                    } else {
                        outFile.write(buf);
                    }

                } else {
                    targetFileSize = outFile.size();
                    break;
                }

                // 清空缓冲   
                buf.clear();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        Long timeConsuming = Duration.between(startTime, LocalDateTime.now()).toMillis();
        logger.info("拷贝文件结束,耗时=" + timeConsuming / 1000 + "s");
        return targetFileSize;
    }

    /**
     * 是否是换行符
     *
     * @param b
     * @return
     */
    private static boolean isLineBreakChar(byte b) {
        char ss = (char) b;
        return '\n' == ss;
    }

    private static byte[] getArrToLastLineBreakChar(byte[] arr) {

        int lastIndex = arr.length;
        for (int i = lastIndex - 1; i >= 0; i--) {
            //找出最后一个换行符'\n'
            if (isLineBreakChar(arr[i])) {
                lastIndex = i;
                break;
            }
        }

        return Arrays.copyOfRange(arr, 0, lastIndex);
    }

    private static String getTargetFilePath(String srcFilePath, String replaceStr) {
        CommonFile commonFile = getCommonFile(srcFilePath);
        String targetFileName = commonFile.getFileNameFmt().replace("{timestamp}", replaceStr);
        return commonFile.getParentPath() + "\\" + targetFileName;
    }

    /**
     * 分割文件,速度快(自测中文也不会乱码),78MB:毫秒级
     *
     * @param srcFilePath
     * @param perMb    1M * perModel
     */
    public static void cutFile1(String srcFilePath, int perMb) {
        logger.info("分割文件开始.......");
        LocalDateTime startTime = LocalDateTime.now();
        CommonFile commonSrcFile = getCommonFile(srcFilePath);
        long maxSize = commonSrcFile.getFileSize();
        int fileNumber = 0;

        long start = 0L;
        long perFileSize = (2 << 9) * (2 << 9) * perMb;
        long end = perFileSize;

        while (true) {
            long targetFileSize = copyFile(srcFilePath, start, end, "_" + (++fileNumber));

            if (end >= maxSize) {
                break;
            }

            start += targetFileSize;
            end = (end >= maxSize) ? maxSize : start + perFileSize;
        }


        Long timeConsuming = Duration.between(startTime, LocalDateTime.now()).toMillis();
        logger.info("分割文件结束,耗时=" + timeConsuming / 1000 + "s");
    }

    /**
     * 性能比较差:96.3M 用了612s
     * 由于是行读,中文文件不乱码
     *
     * @param filePath
     * @param perFileSize
     * @param charSet
     */
    public static void cutFile2(String filePath, long perFileSize, String charSet) {
        //大文件大小
        logger.info("分割文件开始.......");
        LocalDateTime startTime = LocalDateTime.now();
        CommonFile commonFile = getCommonFile(filePath);

        try (FileInputStream inputStream = new FileInputStream(filePath);
             Scanner sc = new Scanner(inputStream, charSet)
        ) {
            int sonNum = 1;
            String sonFilePath = commonFile.getParentPath();
            String sonFileName = commonFile.getFileNameFmt().replace("{timestamp}",
                    createFileNameTimeStame(sonNum));
            sonFilePath += "\\" + sonFileName;

            while (sc.hasNextLine()) {

                long sonFileCurrentSize = randomWrite2File(sc.nextLine() + "\n", sonFilePath, true, 1024 * 10);

                if (sonFileCurrentSize >= perFileSize) {
                    sonFileName = commonFile.getFileNameFmt().replace("{timestamp}",
                            createFileNameTimeStame(++sonNum));
                    sonFilePath = commonFile.getParentPath() + "\\" + sonFileName;
                }
            }

            Long timeConsuming = Duration.between(startTime, LocalDateTime.now()).toMillis();
            logger.info("分割文件结束,耗时=" + timeConsuming / 1000 + "s");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static class CommonFile {
        private String fileName;
        private long fileSize;
        private String parentPath;
        private String fileNameFmt;

        public CommonFile() {
        }

        public CommonFile(String fileName, long fileSize) {
            this.fileName = fileName;
            this.fileSize = fileSize;
        }

        public String getFileName() {
            return fileName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public long getFileSize() {
            return fileSize;
        }

        public void setFileSize(long fileSize) {
            this.fileSize = fileSize;
        }

        public String getParentPath() {
            return parentPath;
        }

        public void setParentPath(String parentPath) {
            this.parentPath = parentPath;
        }

        public String getFileNameFmt() {
            int lastDot = fileName.lastIndexOf(".");

            String prefix = fileName.substring(0, lastDot);
            //文件后缀名
            String postfix = fileName.substring(lastDot + 1);
            fileNameFmt = prefix + "{timestamp}" + "." + postfix;
            return fileNameFmt;
        }

        public void setFileNameFmt(String fileNameFmt) {
            this.fileNameFmt = fileNameFmt;
        }

        @Override
        public String toString() {
            return "CommonFile{" +
                    "fileName='" + fileName + '\'' +
                    ", fileSize=" + fileSize +
                    ", parentPath='" + parentPath + '\'' +
                    ", fileNameFmt='" + getFileNameFmt() + '\'' +
                    '}';
        }
    }


    public static void main(String[] args) throws IOException {
        //String str = "发生肯德基发生大师傅士大夫 \n  发生打开房间啊开始JFK \n";
        String filePath = ProjectPathUtils.getRootPath("/file/test.txt");

        //System.out.println(str.length());
        //System.out.println(str.getBytes().length);

        /*for(int i =0;i < 1000000;i++){
            long fileSize = randomWrite2File(i+ ":" +str, filePath, true,1024);
            System.out.println("fileSize = " + fileSize);
        }*/
        //0999420
        //copyFile(filePath);

        cutFile1(filePath, 80);

        //System.out.println(getCommonFile(filePath));

        /*String str1 = CommonFileUtils.scannerReadFile(filePath, "UTF-8");
        System.out.println(str1);*/
    }
}

 

posted @ 2019-04-22 17:06  小传风  阅读(189)  评论(0编辑  收藏  举报