1. 程式人生 > >java多執行緒讀寫檔案

java多執行緒讀寫檔案

一、引言

    使用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 + "條資料");
	}
}

七、總結

    本文中檔案的解析和寫出採用了多線,如果可以起三個執行緒:一個執行緒讀、一個執行緒解析、一個執行緒寫,三個執行緒同時工作可以大大提高讀寫效率。歡迎評論探討!

Copyright ©2018 hbgengfei11