java多執行緒讀寫檔案
阿新 • • 發佈:2019-02-04
一、引言
使用java讀寫檔案是日常工作中需要經常使用的技術。為了提高檔案寫出分析和寫出效率,本文采用多執行緒實現多檔案解析和寫出。具體實現如下:
二、檔案讀寫工具類
package com.test.multiThreadsReadFile.utils; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.univocity.parsers.csv.CsvWriter; import com.univocity.parsers.csv.CsvWriterSettings; /** * @author admin 檔案讀寫工具類 */ public class FileUtil { /** * 讀取txt檔案工具類 * @param inputPath * @return */ public static Map<String,List<String>> readTxtFile(String inputPath) { Map<String,List<String>> map = new HashMap<String,List<String>>(); List<String> aList = new ArrayList<String>(); List<String> bList = new ArrayList<String>(); List<String> cList = new ArrayList<String>(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader( new FileInputStream(inputPath), "UTF-8"),10*1024*1024); String line = ""; while((line = reader.readLine()) != null) { if(null == line || line.isEmpty()) { continue; } String[] split = line.split("="); if(split.length < 2) { continue; } if(split[0].equals("a")) { aList.add(split[1]); } if(split[0].equals("b")) { bList.add(split[1]); } if(split[0].equals("c")) { cList.add(split[1]); } } map.put("a", aList); map.put("b", bList); map.put("c", cList); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return map; } /** * 寫出CSV檔案工具類 * * @param os * @param headers * @param rows * @throws IOException */ public static void writerCSVFile(String outputPath, List<String> headers, List<Object[]> rows,String prefixName) { String fileName = prefixName + ".csv"; // 新建需要寫出的檔案 File file = new File(outputPath,fileName); Writer writer = null; try { // 如果寫出地址是個資料夾,建立新檔案 if (file.isDirectory()) { file.createNewFile(); } writer = new FileWriter(file, true); // 建立檔案寫出流 // 建立CSV檔案寫出設定 CsvWriterSettings setting = new CsvWriterSettings(); // 寫出檔案,並可以追加 CsvWriter csvwriter = new CsvWriter(writer, setting); // 寫出檔案標題 csvwriter.writeHeaders(headers); // 寫出檔案內容 csvwriter.writeRowsAndClose(rows); } catch (IOException e) { e.printStackTrace(); } finally { try { if (null != writer) { // 關閉檔案寫出流 writer.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
三、業務介面類
package com.test.multiThreadsReadFile.service;
/**
* @author admin
* 檔案讀寫介面
*/
public interface IService
{
/**
* 檔案讀取主方法
* @param inputPath
* @param outputPath
* @return
*/
long readFile(String inputPath,String outputPath);
}
四、業務實現類
package com.test.multiThreadsReadFile.service.impl; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.test.multiThreadsReadFile.service.IService; import com.test.multiThreadsReadFile.utils.FileUtil; public class TxtFileService implements IService { /* * 讀取檔案,開啟執行緒主方法 */ @Override public long readFile(String inputPath,String outputPath) { //統計解析成功條數 long successNum = 0; //讀取全部檔案 Map<String, List<String>> readTxtFile = FileUtil.readTxtFile(inputPath); //解析成功條數統計 Hashtable<String, Long> successCount = new Hashtable<String, Long>(); //獲取標題 List<String> head = getHead(); //組裝執行緒名字,既檔案字首 String[] fileName = { "a", "b", "c" }; // 建立計數器 // 構造引數傳入的數量值代表的是latch.countDown()呼叫的次數 CountDownLatch latch = new CountDownLatch(3); // 建立執行緒池,可以通過以下方式建立 ExecutorService threadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < fileName.length; i++) { threadPool.execute(new ReadTxtFileThread(readTxtFile, head, latch, fileName[i], successCount,outputPath)); } try { // 阻塞當前執行緒,直到所有執行緒都執行完畢 latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } finally { //所有業務執行完畢,關閉執行緒池 threadPool.shutdown(); } //解析成功條數統計 for (Long num : successCount.values()) { successNum += num; } return successNum; } /** * 組裝檔案表頭 * @return */ private List<String> getHead() { List<String> head = new ArrayList<String>(); head.add("A1"); head.add("A2"); head.add("A3"); return head; } }
五、解析與寫出檔案執行緒
package com.test.multiThreadsReadFile.service.impl; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import com.test.multiThreadsReadFile.utils.FileUtil; /** * @author admin * 檔案寫出執行緒 */ public class ReadTxtFileThread implements Runnable { /** * 讀取來的資料 */ private Map<String, List<String>> allLines; /** * 表頭 */ private List<String> head; /** * 執行緒計數 */ private CountDownLatch latch; /** * 執行緒name */ private String ThreadName; /** * 檔案寫出地址 */ private String outputPath; /** * 統計 */ private Hashtable<String, Long> successCount; public ReadTxtFileThread(Map<String, List<String>> allLines, List<String> head, CountDownLatch latch, String threadName, Hashtable<String, Long> successCount,String outputPath) { super(); this.allLines = allLines; this.head = head; this.latch = latch; this.ThreadName = threadName; this.successCount = successCount; this.outputPath = outputPath; } @Override public void run() { //通過判斷執行緒名字來決定執行那個執行緒 String[] str = {"a","b","c"}; for (String name : str) { if(name.equals(ThreadName)) { writeTxtFile(name); } } //執行緒計數 latch.countDown(); } /** * 解析並寫出檔案 * @param type */ private synchronized void writeTxtFile(String type) { //每個檔案寫出條數統計 long sucNum = 0; //需要寫出的行 List<Object[]> rows = new ArrayList<Object[]>(); //生成檔案標題 String prefixName = type + System.currentTimeMillis(); //需要寫出的檔案的原始資料 List<String> list = allLines.get(type); //根據需求解析檔案 for (String line : list) { String[] split = line.split(","); rows.add(split); } //統計單個檔案成功條數 sucNum = rows.size(); successCount.put(type, sucNum); //呼叫工具類,寫出CSV檔案 FileUtil.writerCSVFile(outputPath, head, rows,prefixName); } }
六、測試
package com.test.multiThreadsReadFile.test;
import com.test.multiThreadsReadFile.service.IService;
import com.test.multiThreadsReadFile.service.impl.TxtFileService;
/**
* @author admin
* 測試類
*/
public class MyTest
{
public static void main(String[] args)
{
//讀取檔案地址
String inputPath = "C:\\Users\\test\\Desktop\\demo.txt";
//寫出檔案地址
String outputPath = "C:\\Users\\test\\Desktop\\1\\";
IService readTxt = new TxtFileService();
long readFile = readTxt.readFile(inputPath, outputPath);
System.out.println("成功解析" + readFile + "條資料");
}
}
七、總結
本文中檔案的解析和寫出採用了多線,如果可以起三個執行緒:一個執行緒讀、一個執行緒解析、一個執行緒寫,三個執行緒同時工作可以大大提高讀寫效率。歡迎評論探討!