这个问题已经有一个答案在这里:

不言自明,我试过谷歌的,并得到了很多可怕的expertsexchange,我搜寻了这里也无济于事。一个在线教程或例子就是最好的。谢谢你们.

有帮助吗?

解决方案

如果你真的这样做是操纵CSV文件本身,纳尔逊的答案是有道理的。但是,我怀疑的是,CSV只是一个项目的问题你的解决。C++,这可能意味着你有什么喜欢这个作为你的数据模型:

struct Customer {
    int id;
    std::string first_name;
    std::string last_name;
    struct {
        std::string street;
        std::string unit;
    } address;
    char state[2];
    int zip;
};

因此,当你跟一个数据集合,很有意义 std::vector<Customer>std::set<Customer>.

考虑到这一点,想想你的CSV处理作为两个操作:

// if you wanted to go nuts, you could use a forward iterator concept for both of these
class CSVReader {
public:
    CSVReader(const std::string &inputFile);
    bool hasNextLine();
    void readNextLine(std::vector<std::string> &fields);
private:
    /* secrets */
};
class CSVWriter {
public:
    CSVWriter(const std::string &outputFile);
    void writeNextLine(const std::vector<std::string> &fields);
private:
    /* more secrets */
};
void readCustomers(CSVReader &reader, std::vector<Customer> &customers);
void writeCustomers(CSVWriter &writer, const std::vector<Customer> &customers);

读和写一个单一行的时间,而不是保持一个完整的存中表示的该文件本身。有一些明显的益处:

  1. 你的数据表示在形成有意义的对你的问题(用户),而不是目前的解决方案(CSV文件)。
  2. 你可以平凡添加适配器对于其他数据格式,诸如批量SQL进口/出口、Excel/OO电子表格文件,或甚至HTML <table> 渲染。
  3. 你的记忆足迹可能是较小的(取决于相对 sizeof(Customer) 与该数字在一个单一的行)。
  4. CSVReaderCSVWriter 可以重复使用为基础,在存储器模型(例如纳尔逊的)不失性能或功能。相反是不正确的。

其他提示

更多信息将是有益的。

但是,最简单的形式:

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

int main()
{
    std::ifstream  data("plop.csv");

    std::string line;
    while(std::getline(data,line))
    {
        std::stringstream  lineStream(line);
        std::string        cell;
        while(std::getline(lineStream,cell,','))
        {
            // You have a cell!!!!
        }
    }
 }

还看到这样一个问题: CSV分析器在C++

你可以尝试提高分析器库,特别是 逃列表中分离器

我已经工作了很多的CSV文件在我的时间。我想添加建议:

1-根据来源(Excel,等等),逗号或标签可能埋在一个领域。通常的规则是,他们将'保护',因为该领域将是双倍价格分隔,在"麻萨诸塞州波士顿02346".

2-一些来源不会双引界定的所有文本的领域。其他来源。其他人会划定的所有领域,甚至数字.

3域包含双报价通常得到嵌入的双引号倍上涨(和该领域本身的分隔与双引号,如"乔治"的"贝贝""鲁斯".

4-一些消息来源将嵌入CR/劳动力调查(Excel是这个!).有时,它将只是一个CR。该领域通常将以双引号的分隔,但这种情况是非常难以处理。

这是一个很好的锻炼自己的工作:)

你应该打断你的图书馆分成三部分

  • 装载CSV文件
  • 代表文件中的记忆这样你可以修改和阅读它
  • 保存CSV文件回到磁盘

所以你正在写一CSVDocument类,包括:

  • 负载(const char*文件);
  • 保存(const char*文件);
  • GetBody

所以,你可以用你的图书馆是这样的:

CSVDocument doc;
doc.Load("file.csv");
CSVDocumentBody* body = doc.GetBody();

CSVDocumentRow* header = body->GetRow(0);
for (int i = 0; i < header->GetFieldCount(); i++)
{
    CSVDocumentField* col = header->GetField(i);
    cout << col->GetText() << "\t";
}

for (int i = 1; i < body->GetRowCount(); i++) // i = 1 so we skip the header
{
    CSVDocumentRow* row = body->GetRow(i);
    for (int p = 0; p < row->GetFieldCount(); p++)
    {
        cout << row->GetField(p)->GetText() << "\t";
    }
    cout << "\n";
}

body->GetRecord(10)->SetText("hello world");

CSVDocumentRow* lastRow = body->AddRow();
lastRow->AddField()->SetText("Hey there");
lastRow->AddField()->SetText("Hey there column 2");

doc->Save("file.csv");

这给我们下面的接口:

class CSVDocument
{
public:
    void Load(const char* file);
    void Save(const char* file);

    CSVDocumentBody* GetBody();
};

class CSVDocumentBody
{
public:
    int GetRowCount();
    CSVDocumentRow* GetRow(int index);
    CSVDocumentRow* AddRow();
};

class CSVDocumentRow
{
public:
    int GetFieldCount();
    CSVDocumentField* GetField(int index);
    CSVDocumentField* AddField(int index);
};

class CSVDocumentField
{
public:
    const char* GetText();
    void GetText(const char* text);
};

现在你只需要填补空白从这里:)

相信我,当我说这个-投资你的时间到学习如何使图书馆,尤其是那些涉及装载、操作和保存的数据,不仅会去除你的依赖性上存在这样的图书馆,但也会让你有更好的程序员。

:)

编辑

我不知道你已经知道的关于字符串操纵和分析;所以如果你被卡住,我会乐于帮助。

这里是一些代码可以使用。数据从csv是内部保存的一系列行。每行一系列的串。希望这会有所帮助。

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
typedef std::string String;
typedef std::vector<String> CSVRow;
typedef CSVRow::const_iterator CSVRowCI;
typedef std::vector<CSVRow> CSVDatabase;
typedef CSVDatabase::const_iterator CSVDatabaseCI;
void readCSV(std::istream &input, CSVDatabase &db);
void display(const CSVRow&);
void display(const CSVDatabase&);
int main(){
  std::fstream file("file.csv", std::ios::in);
  if(!file.is_open()){
    std::cout << "File not found!\n";
    return 1;
  }
  CSVDatabase db;
  readCSV(file, db);
  display(db);
}
void readCSV(std::istream &input, CSVDatabase &db){
  String csvLine;
  // read every line from the stream
  while( std::getline(input, csvLine) ){
    std::istringstream csvStream(csvLine);
    CSVRow csvRow;
    String csvCol;
    // read every element from the line that is seperated by commas
    // and put it into the vector or strings
    while( std::getline(csvStream, csvCol, ',') )
      csvRow.push_back(csvCol);
    db.push_back(csvRow);
  }
}
void display(const CSVRow& row){
  if(!row.size())
    return;
  CSVRowCI i=row.begin();
  std::cout<<*(i++);
  for(;i != row.end();++i)
    std::cout<<','<<*i;
}
void display(const CSVDatabase& db){
  if(!db.size())
    return;
  CSVDatabaseCI i=db.begin();
  for(; i != db.end(); ++i){
    display(*i);
    std::cout<<std::endl;
  }
}

使用提高分析器来分析的记录, 在这里看到更多细节.

ifstream in(data.c_str());
if (!in.is_open()) return 1;

typedef tokenizer< escaped_list_separator<char> > Tokenizer;

vector< string > vec;
string line;

while (getline(in,line))
{
    Tokenizer tok(line);
    vec.assign(tok.begin(),tok.end());

    /// do something with the record
    if (vec.size() < 3) continue;

    copy(vec.begin(), vec.end(),
         ostream_iterator<string>(cout, "|"));

    cout << "\n----------------------" << endl;
}

看看实践编程'(TPOP)通过Kernighan&梭子鱼。它包括一个实例的分析CSV文件中的C和C++。但是,这将是值得一读的书甚至如果你不使用的代码。

(先前的网址: http://cm.bell-labs.com/cm/cs/tpop/)

我发现这个有趣的方法:

CSV C结构的效用

引用:CSVtoC是一个程序,需要一个CSV或逗号分隔值的文件作为输入和转储它作为一C的结构。

当然,你不能改变CSV文件,但是如果你只是需要在记忆只读取到数据,它可以工作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top