在符合标准的二进制文件中包含CSV文件 [英] Include CSV File in Complied Binary

查看:23
本文介绍了在符合标准的二进制文件中包含CSV文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将CSV文件编译到我的Binary中,这样当我运行EXE应用程序时,它不需要文件夹中所需的CSV文件,并且EXE中已包含CSV文件数据.

I want to compile a CSV file into my Binary so that when I run my EXE application it does not need the required CSV file in the folder, and has the CSV files data within the EXE already.

例如,我有多个CSV文件,其中包含2列和150+行字符串,我希望在运行时将其解析为C ++映射.当我使用此应用程序时,我不希望它位于包含多个CSV文件的文件夹中,而只是更容易携带的EXE.如果这些CSV文件中的数据必须更改,那么我只需使用更新的CSV文件来重新构建解决方案.

For instance I have multiple CSV files with 2 columns and 150+ rows of strings which I want to, at runtime, be parsed into a C++ map. When I use this application I dont want it to be in a folder with multiple CSV files, rather just the EXE which can be more portable. If the data in these CSV files had to change then I would simply re-build the solution with updated CSV files.

C ++能够做到这一点吗?如果是这样,我该怎么做?我不是在寻找我想要的设计方式的替代方案,我想让它列出我的描述方式,并且如果不可能的话,我将在头文件中创建一个数组或枚举.

Is C++ able to do this? If so how would I do this? I'm not looking for alternatives to how I want this designed, I would like to have it set out how I have described, and if it is not possible I will just create an array or enum within a header file.

推荐答案

在这里,我喜欢一些人的建议,并为"csv"到"c ++ header"文件编译器创建了一个工作示例.

I like the proposal of some guys here and created a working example for a "csv" to "c++ header" file compiler.

它甚至可以处理不同列大小的CSV.

It will even deal with different column sized CSVs.

将结果存储为 std :: string_view 的数组的compile-time-constexpr数组.

It stores the result as compile-time-constexpr array of array of std::string_view.

也许它可以给您基本概念:

Maybe it can give you the basic idea:

#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用作输出文件.当然,您可以使用所需的任何文件(流).

Because I do not have files here on SO, I used std::istringstream as input and std::cout as output file. You can of course use whatever file (stream) you like.

这篇关于在符合标准的二进制文件中包含CSV文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆