我想将一个 CSV 文件编译到我的二进制文件中,这样当我运行我的 EXE 应用程序时,它不需要文件夹中的所需 CSV 文件,并且已经在 EXE 中包含 CSV 文件数据。
例如,我有多个包含 2 列和 150 多行字符串的 CSV 文件,我希望在运行时将其解析为 C++ 映射。当我使用这个应用程序时,我不希望它位于包含多个 CSV 文件的文件夹中,而只是 EXE,这样可以更便携。如果这些 CSV 文件中的数据必须更改,那么我只需使用更新后的 CSV 文件重新构建解决方案。
C++ 能做到这一点吗?如果是这样,我该怎么做?我不是在寻找我想要的设计方式的替代方案,我想让它阐明我所描述的方式,如果不可能,我将只在头文件中创建一个数组或枚举。
最佳答案
我喜欢这里一些人的提议,并为“csv”到“c++ header”文件编译器创建了一个工作示例。
它甚至可以处理不同列大小的 CSV。
它将结果存储为std::string_view
数组的compile-time-constexpr 数组。
也许它可以给你基本的想法:
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <regex>
#include <sstream>
#include <fstream>
#include <algorithm>
// The delimiter
const std::regex re(",");
std::istringstream sourceCSV1{R"(A00,A01,A02
A10,A11,A12
A20,A21,A22)"};
std::istringstream sourceCSV2{R"(B00,B01
B10,B11,B12,B13,B14
B20,B21,B22,B23)"};
// Define Alias for Easier Reading
using Columns = std::vector<std::string>;
using CSV = std::vector<Columns>;
// Proxy for the input Iterator
struct ColumnProxy {
// Overload extractor. Read a complete line
friend std::istream& operator>>(std::istream& is, ColumnProxy& cp) {
// Read a line
std::string line; cp.columns.clear();
std::getline(is, line);
// Split values and copy into resulting vector
std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1),
std::sregex_token_iterator(),
std::back_inserter(cp.columns));
return is;
}
// Type cast operator overload. Cast the type 'Columns' to std::vector<std::string>
operator std::vector<std::string>() const { return columns; }
protected:
// Temporary to hold the read vector
Columns columns{};
};
void convertCSV2Hpp(std::istream& is, std::ostream& os, std::string& variableName)
{
// Read complete CSV File
CSV csvFile { std::istream_iterator<ColumnProxy>(is), std::istream_iterator<ColumnProxy>() };
// Get maximumn number of columns in CSV file
size_t maxCols = std::max_element(csvFile.begin(),csvFile.end(),[](const Columns& c1, const Columns& c2){ return c1.size() < c2.size();})->size();
// Build output header file
std::string includeGuard(variableName);
std::transform(variableName.begin(), variableName.end(),includeGuard.begin(), ::toupper);
// Print header of file
os << "#ifndef " << includeGuard << "_HPP" << "\n#define " << includeGuard << "_HPP\n\n#include <string>\n#include <array>\n\n"
<< "constexpr size_t " << variableName << "NumberOfRows {" << csvFile.size() << "U};\n"
<< "constexpr size_t " << variableName << "NumberOfColumns {" << maxCols << "U};\n\n"
<< "constexpr std::array<std::array<std::string_view," << variableName << "NumberOfColumns" << ">," << variableName << "NumberOfRows" << "> " << variableName << " {{";
// Print data
for (size_t row = 0U; row < csvFile.size(); ++row) {
os << "\n{";
for (size_t col=0U; col<maxCols; ++col) {
os << "\"" << ((col < csvFile[row].size())?csvFile[row][col]:"") << "\"" << ((col==maxCols-1)?"":", ");
}
os << "},";
}
os << "\n}};\n\n#endif\n\n";
}
int main()
{
std::string name("csv1");
convertCSV2Hpp(sourceCSV1,std::cout,name);
name = "csv2";
convertCSV2Hpp(sourceCSV2,std::cout,name);
return 0;
}
因为我这里没有关于 SO 的文件,所以我使用 std::istringstream
作为输入,std::cout 作为输出文件。您当然可以使用任何您喜欢的文件(流)。
关于c++ - 在编译的二进制文件中包含 CSV 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57520427/