(11)多线程的运用(1)----将大文件解析成多个小文件

这篇文章写得不错:https://www.cnblogs.com/metoy/p/4470418.html?utm_source=tuicool&utm_medium=referral

1.背景:目前有一个约有一个300MB的文本文件,需要将里面的数据提取出来存到数据库。

2.解决思路:我是将这个300MB的文件切割成31个相同大小的文件 ,然后使用10个线程解析这31个文件,每个线程处理三个文件,使用 synchronized 关键字对文件资源加锁,防止一个文件被俩个线程读到。大约测试一下时间在6-7秒。

synchronized关键字:能够保证同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果

可以看下这篇文章:https://www.cnblogs.com/YpfBolg/p/10805496.html

3.话不多说,上代码! 如果写的不错的话,大家点个赞鼓励一下, 如有写的不完善的地方,欢迎大家在评论区指出,共同进步!

​
 /***
     * 解析文件内容
     */
    @Test
    public void parseFileContent() {
        Long startTime = System.currentTimeMillis();
        Map<String, File> map = new HashMap<String, File>();
        //将这个路径形成一个唯一标识(加上文件名称) 可以区分存储的文件
        String uploadPath = "D:/testFile/test.txt";
        FileUtil fileUtil = new FileUtil();
        fileUtil.parseFile(uploadPath);
        //接下来遍历整个文件夹里的31个分割后的文件
        File[] files = new File("D:/testFile").listFiles();
        String fileName = "";
        for (File fileInfo : files) {
            if (fileInfo.isFile() && fileInfo.exists() && fileInfo.getName().contains("part")) {
                fileName = fileInfo.getName();
                map.put(fileName, fileInfo);
            }
        }
        //创建自定义线程对象(开启10个线程来解析这三十一个文件)
        FileThreadResource resource = new FileThreadResource();
        for (int k = 0; k < 10; k++) {
            ParseFileThread mt = new ParseFileThread(map, resource);
            mt.run();
        }
        Long endTime = System.currentTimeMillis();
        System.out.println("总共花了--"+(endTime -startTime)/1000+"---秒");
    }

​

4.接下来我将代码中涉及的一些类贴上来!

 A.FileUtil中的类

public void parseFile(String fileUrl) {
    try {
        long timer = System.currentTimeMillis();
        //设读取文件的缓存为20MB
        int bufferSize = 20 * 1024 * 1024;
        //建立缓冲文本输入流
        File file = new File(fileUrl);
        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        //注意这里有时会乱码,根据自己的文本存储格式,进行调整
        InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream, "utf-8");
        BufferedReader input = new BufferedReader(inputStreamReader, bufferSize);
        long fileSize = getLineNumber(file);
        //要分割的块数减一,这里表示分割为31个文件
        int splitNum = 30;
        //fileLines表示我的输入本文的行数,由于每行文本较长,所有存储占用较大
        int fileLines = (int) fileSize;
        //分割后存储每个块的行数
        long perSplitLines = fileLines / splitNum;
        for (int i = 0; i <= splitNum; ++i) {
            //分割
            //每个块建立一个输出
            BufferedWriter output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("D:/testFile/" + "part" + i + ".txt")), "utf-8"));
            String line = null;
            //逐行读取,逐行输出
            for (long lineCounter = 0; lineCounter < perSplitLines && (line = input.readLine()) != null; ++lineCounter) {
                output.append(line + "\r");
            }
            output.flush();
            output.close();
            output = null;
        }
        input.close();
        timer = System.currentTimeMillis() - timer;
        logger.info("分割文件处理时间:" + timer);
    } catch (Exception e) {
        logger.error("分割文件异常---", e);
    }
}
 /**
     * 获取整个文件有多少行
     * @param file
     * @return
     */
    public long getLineNumber(File file) {
        if (file.exists()) {
            try {
                FileReader fileReader = new FileReader(file);
                LineNumberReader lineNumberReader = new LineNumberReader(fileReader);
                lineNumberReader.skip(Long.MAX_VALUE);
                long lines = lineNumberReader.getLineNumber() + 1;
                fileReader.close();
                lineNumberReader.close();
                return lines;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }

 

/**
    用来解析文件的线程
 * @Author: tanghh18
 * @Date: 2019/8/5 18:54
 */
public class ParseFileThread extends FileThreadResource implements Runnable {
    private Map<String, File> map;
    private FileThreadResource resource;

    public ParseFileThread(Map<String, File> map, FileThreadResource resource) {
        this.map = map;
        this.resource = resource;
    }

    @Override
    public void run() {
        synchronized (resource) {
            int i = resource.getFileIndex();
            for (int j = 1; j <= 3; j++) {
                File file = map.get("part" + i + ".txt");
                try {
                    List<String> logInfoList = importFile(file, "utf-8");
                    System.out.println("总共多少条数据---"+logInfoList.size());
                    i++;
                    resource.setFileIndex(i);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 8.读取.txt文件中的数据,存入集合中
     */
    public List<String> importFile(File file, String encoding) throws IOException, ParseException {
        List<String> allLineList = new ArrayList<>();
        InputStreamReader reader = null;
        String line = "";
        try {
            reader = new InputStreamReader(new FileInputStream(file), encoding);
            BufferedReader bufferedReader = new BufferedReader(reader);
            while ((line = bufferedReader.readLine()) != null) {
                allLineList.add(line);
            }
        } catch (Exception e) {
        }
        return allLineList;
    }

}

 

/**
 * 功能描述: 所有线程共享这个资源类
 * @Author: tanghh18
 * @Date: 2019/7/24 9:51
 */
public class FileThreadResource {
    /**
     * 定义一个初始化变量
     */
    private Integer fileIndex=0;

    public Integer getFileIndex() {
        return fileIndex;
    }

    public void setFileIndex(Integer fileIndex) {
        this.fileIndex = fileIndex;
    }
}

5,最后看一下效果。首先是分割后的文件。

6.其次是程序执行效果。

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值