포스트

(c++) csv 파일 입출력

c, c++, vs, csv, excel, ifstream, ofstream, std::ifstream, std::ofstream, tellp, map, lambda function

csv

  • 최초 작성일: 2023년 8월 3일 (목)

##

  1. std::map<std::string, std::string> lines : CSV 파일의 각 행을 저장. 키는 시리얼 번호이고, 값은 해당 시리얼 번호에 해당하는 전체 행이다.
  2. auto escapeCSV 람다 함수 : 특정 필드(데이터 값)가 CSV 파일에서 제대로 처리되도록 이스케이프한다. 예를 들어, 데이터 값에 쉼표가 포함되어 있으면, 이것은 CSV에서 새로운 필드를 생성하는 데 사용되는 구분자로 해석될 수 있으므로, 이스케이프 처리가 필요.
  3. 파일 읽기 : ifstream을 사용하여 CSV 파일을 열고, 각 행을 읽어서 시리얼 번호와 행을 map에 저장.
  4. 새로운 행 구성 : 각각의 변수(예: SerialNumber, MacWifi, SWVer 등)는 escapeCSV 함수를 통해 안전하게 이스케이프 처리되고, 이들은 쉼표로 구분되어 새로운 CSV 행을 생성한다.
  5. 행 업데이트 또는 추가 : 새로 생성된 행은 map에 추가됩니다. 이미 같은 시리얼 번호를 가진 행이 있다면, 그 행은 새로운 행으로 업데이트되고, 그렇지 않다면 새 행이 추가된다.
  6. 파일 쓰기 : map에 있는 모든 행을 다시 CSV 파일에 쓴다. 파일이 처음 생성되는 경우에는 헤더도 추가.


이 함수의 주요 목적은 특정 시리얼 번호에 대한 행을 CSV 파일에서 업데이트 하는 것. 만약 해당 시리얼 번호에 대한 행이 없다면 새로운 행을 추가하고, 있다면 기존 행을 업데이트 한다.


##

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
void UpdateCSV() {
	try {
		CString fileName;
		fileName.Format(_T(".\\result\\All_results.csv"));

		// Map for lines
		std::map<std::string, std::string> lines;

		// CSV Escape Function as a lambda expression
		auto escapeCSV = [](const std::string& field) {
			if (field.find(',') != std::string::npos || field.find('\n') != std::string::npos || field.find('\"') != std::string::npos) {
				return "\"" + std::regex_replace(field, std::regex("\""), "\"\"") + "\"";
			}
			return field;
		};

		// File input
		std::ifstream inFile(fileName);
		if (inFile.fail()) {
			throw std::runtime_error("File could not be opened.\n");
		}

		std::string strCsv;
		while (std::getline(inFile, strCsv)) {
			if (!strCsv.empty()) {
				// Extract ID
				std::string id = strCsv.substr(0, strCsv.find(','));
				lines[id] = strCsv;
			}
		}
		inFile.close();

		// Convert CString to string
		std::string idStr = CT2CA(IdField.GetString());

		// Construct new line
		std::string newLine = escapeCSV(idStr) + ","
			+ escapeCSV(Field1) + ","
			+ escapeCSV(Field2) + " (" + escapeCSV(ResField2) + ")" + ","
			+ escapeCSV(Field3) + " (" + escapeCSV(ResField3) + ")" + ","
			+ escapeCSV(Field4) + " (" + escapeCSV(ResField4) + ")" + ","
			+ escapeCSV(Field5) + " (" + escapeCSV(ResField5) + ")" + ","
			+ escapeCSV(Field6) + " (" + escapeCSV(ResField6) + ")" + ","
			+ escapeCSV(Field7) + " (" + escapeCSV(ResField7) + ")" + ","
			+ escapeCSV(Field8) + " " + escapeCSV(ResField8) + " (" + escapeCSV(ResField9) + ")" + ","
			+ escapeCSV(Field9) + " (" + escapeCSV(ResField10) + ")" + ","
			+ escapeCSV(ResField11) + "/" + escapeCSV(ResField12) + "(" + escapeCSV(ResField13) + " " + escapeCSV(ResField14) + ")" + " (" + escapeCSV(ResField15) + ")" + ","
			+ "=\"" + escapeCSV(Field10) + " " + escapeCSV(Field11) + "\"" + ","
			+ escapeCSV(ResField16) + ","
			+ escapeCSV(ResField17) + "\n";

		// Replace or add line
		lines[idStr] = newLine;

		// File output
		std::ofstream outFile(fileName);
		if (outFile.fail()) {
			throw std::runtime_error("File could not be written.\n");
		}

		// Write header if new file
		if (outFile.tellp() == 0) {
			outFile << "ID,Field1,Field2,Field3,Field4,Field5,Field6,Field7,Field8,Field9,Field10,Field11,Field12,Field13,Field14\n";
		}

		// Write lines
		for (const auto& line : lines) {
			outFile << line.second << '\n';
		}
		outFile.close();
	}
	catch (const std::exception& e) {
		std::cerr << "Caught an exception: " << e.what() << '\n';
	}
}



##

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
void CRadarCalibrationDlg::UpdateCSV() {
	CString fileName;
	fileName.Format(_T(".\\result\\All_results.csv"));

	std::vector<std::string> lines;
	bool addHeader = false;

	// Check if the file exists
	std::ifstream testFile(fileName);
	if (!testFile) {
		// File does not exist, add header
		addHeader = true;
	}
	testFile.close();

	std::ifstream inFile(fileName);
	std::string strCsv;

	if (addHeader) {
		lines.push_back("ID,Field1,Field2,Field3,Field4,Field5,Field6,Field7,Field8,Field9,Field10,Field11,Field12,Field13,Field14\n");
	}

	while (std::getline(inFile, strCsv)) {
		if (!strCsv.empty()) {
			lines.push_back(strCsv + '\n');
		}
	}
	inFile.close();

	std::string idStr = CT2CA(IdField.GetString());

	std::string newLine = idStr + ","
		+ Field1 + ","
		+ Field2 + " (" + ResField2 + ")" + ","
		+ Field3 + " (" + ResField3 + ")" + ","
		+ Field4 + " (" + ResField4 + ")" + ","
		+ Field5 + " (" + ResField5 + ")" + ","
		+ Field6 + " (" + ResField6 + ")" + ","
		+ Field7 + " (" + ResField7 + ")" + ","
		+ Field8 + " " + ResField8 + " (" + ResField9 + ")" + ","
		+ Field9 + " (" + ResField10 + ")" + ","
		+ ResField11 + "/" + ResField12 + "(" + ResField13 + " " + ResField14 + ")" + " (" + ResField15 + ")" + ","
		+ "=\"" + Field10 + " " + Field11 + "\"" + ","
		+ ResField16 + ","
		+ ResField17 + "\n";

	// Check each line to see if the ID is already present.
	auto it = std::find_if(lines.begin(), lines.end(), [&](const std::string& line) {
		return line.substr(0, idStr.length()) == idStr;
		});

	if (it != lines.end()) {
		// If the ID is found, overwrite the line.
		*it = newLine;
	}
	else {
		// If the ID was not found, add a new line.
		lines.push_back(newLine);
	}

	// Write the updated data to the file.
	std::ofstream outFile(fileName);
	for (const auto& line : lines) {
		outFile << line;
	}
	outFile.close();
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.