■ 대용량 CSV 파일을 병합하는 방법을 보여준다.
※ CSV 파일에 헤더 라인이 있어야 합니다.
※ 병합하는 CSV 파일은 동일한 헤더 라인을 갖고 있어야 합니다.
▶ CSVMerger.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
using System; using System.IO; using System.Text; namespace TestProject; /// <summary> /// CSV 병합자 /// </summary> public class CSVMerger { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 로그 쓰기 - WriteLog(message) /// <summary> /// 로그 쓰기 /// </summary> /// <param name="message">메시지</param> public void WriteLog(string message) { Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss")}] {message}"); } #endregion #region 파일 병합하기 - MergeFiles(inputFilePathArray, outputFilePath) /// <summary> /// 파일 병합하기 /// </summary> /// <param name="inputFilePathArray">입력 파일 경로 배열</param> /// <param name="outputFilePath">출력 파일 경로</param> public void MergeFiles(string[] inputFilePathArray, string outputFilePath) { bool isFirstFile = true; using(StreamWriter writer = new StreamWriter(outputFilePath, false, Encoding.UTF8)) { foreach(string inputFilePath in inputFilePathArray) { WriteLog($"CSV 파일 병합을 시작합니다 : {inputFilePath}"); MergeFile(inputFilePath, writer, !isFirstFile); WriteLog($"CSV 파일 병합을 종료합니다 : {inputFilePath}"); isFirstFile = false; } } } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 파일 병합하기 - MergeFile(inputFilePath, writer, skipHeader) /// <summary> /// 파일 병합하기 /// </summary> /// <param name="inputFilePath">입력 파일 경로</param> /// <param name="writer">스트림 라이터</param> /// <param name="skipHeader">헤더 건너뛰기 여부</param> private void MergeFile(string inputFilePath, StreamWriter writer, bool skipHeader) { using(StreamReader reader = new(inputFilePath, Encoding.UTF8)) { if(skipHeader) { reader.ReadLine(); } StringBuilder currentLineStringBuilder = new(); bool insideQuotes = false; while(true) { int characterIntegerValue = reader.Read(); if(characterIntegerValue == -1) { if(currentLineStringBuilder.Length > 0) { writer.WriteLine(currentLineStringBuilder.ToString()); } break; } char character = (char)characterIntegerValue; if(character == '"') { insideQuotes = !insideQuotes; currentLineStringBuilder.Append(character); } else if(character == '\n') { if(insideQuotes) { currentLineStringBuilder.Append(character); } else { writer.WriteLine(currentLineStringBuilder.ToString()); currentLineStringBuilder.Clear(); } } else if(character == '\r') { continue; } else { currentLineStringBuilder.Append(character); } } } } #endregion } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
using System; using System.IO; namespace TestProject; /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main(argumentArray) /// <summary> /// 프로그램 시작하기 /// </summary> /// <param name="argumentArray">인자 배열</param> private static void Main(string[] argumentArray) { CSVMerger csvMerger = new(); if(argumentArray.Length < 2) { csvMerger.WriteLog("프로그램 인자를 2개 지정해주시기 바랍니다."); return; } string inputDicrectoryPath = argumentArray[0]; string outputFilePath = argumentArray[1]; if(!Directory.Exists(inputDicrectoryPath)) { csvMerger.WriteLog("입력 디렉토리 경로가 존재하지 않습니다."); return; } if(File.Exists(outputFilePath)) { csvMerger.WriteLog("출력 파일이 이미 존재합니다."); return; } try { string[] inputFilePathArray = Directory.GetFiles(inputDicrectoryPath, "*.csv"); if(inputFilePathArray.Length == 0) { csvMerger.WriteLog("입력 디렉토리 경로에 CSV 파일이 없습니다."); return; } csvMerger.MergeFiles(inputFilePathArray, outputFilePath); csvMerger.WriteLog($"파일 병합이 완료되었습니다. 출력 파일 : {outputFilePath}"); } catch(Exception exception) { csvMerger.WriteLog($"오류가 발생했습니다 : {exception.Message}"); } } #endregion } |