ソフトウェア開発 C++

CSVファイルを読み書きする

戻る


CSV(comma-separated value)形式のファイルを読み書きするコードは以下の通り。

csv.h
class CsvReader
{
    FILE *m_fp;
public:
    CsvReader() { }
    bool Open(const char *filename)
    {
        m_fp = fopen(filename, "r");
        return m_fp != NULL;
    }
    void Close(void)
    {
        fclose(m_fp);
        m_fp = NULL;
    }
    bool Read(vector<string>& values);
    bool ReadAll(vector<vector<string> >& records);
};

class CsvWriter
{
    FILE *m_fp;
public:
    CsvWriter() { }
    bool Open(const char *filename)
    {
        m_fp = fopen(filename, "wb");
        return m_fp != NULL;
    }
    void Close(void)
    {
        fclose(m_fp);
        m_fp = NULL;
    }
    bool Write(const vector<string>& values);
    bool WriteAll(const vector<vector<string> >& records);
};
csv.cpp
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
using namespace std;

#include "csv.h"

#define BUFSIZE 1024

static void chomp2(string& s)
{
    int len = s.size();
    if (len > 0 && s[len - 1] == '\n')
        s = s.substr(0, len - 1);
}

static void replace_all(string &s, const string& from, const string& to)
{
    string t;
    size_t i = 0;
    while((i = s.find(from, i)) != -1)
    {
        t = s.substr(0, i);
        t += to;
        t += s.substr(i + from.size());
        s = t;
        i += to.size();
    }
}

static bool getline(FILE *fp, string& line)
{
    char buf[BUFSIZE];

    line.clear();
    if (fgets(buf, BUFSIZE, fp) == NULL)
        return false;

    do
    {
        line += buf;
    } while(strchr(buf, '\n') == NULL && fgets(buf, BUFSIZE, fp) != NULL);

    return true;
}

bool CsvReader::Read(vector<string>& values)
{
    string line, line2, s;

    values.clear();
    if (!getline(m_fp, line))
        return false;

    int j = 0;
    int len = line.size();
    while(j < len)
    {
        int i = j;
        if (line[j] == '\n')
        {
            s.clear();
            values.push_back(s);
            break;
        }
        else if (line[j] == '\"')
        {
            i++;
            j++;
redo:       j = line.find('\"', j);
            if (j == -1)
            {
                if (len > 0 && line[len - 1] == '\n')
                {
                    if (getline(m_fp, line2))
                    {
                        j = line.size();
                        line += line2;
                        len = line.size();
                        goto redo;
                    }
                }
                j = len;
            }
            else if (line[j + 1] == '\"')
            {
                j += 2;
                goto redo;
            }
            s = line.substr(i, j - i);
            replace_all(s, "\"\"", "\"");
            values.push_back(s);
            if (line[j] == '\"')
            {
                j++;
                if (line[j] == ',' || line[j] == '\n')
                    j++;
            }
        }
        else
        {
            j = line.find(',', j);
            if (j != -1)
            {
                values.push_back(line.substr(i, j - i));
                j++;
            }
            else
            {
                chomp2(line);
                values.push_back(line.substr(i));
                break;
            }
        }
    }
    return true;
}

bool CsvReader::ReadAll(vector<vector<string> >& records)
{
    vector<string> values;

    records.clear();
    while(Read(values))
    {
        records.push_back(values);
    }
    return ferror(m_fp) == 0;
}

bool CsvWriter::Write(const vector<string>& values)
{
    string record, s, t;

    if (values.size() > 0)
    {
        s = values[0];
        if (s.find(',') != -1 || s.find('\"') != -1)
        {
            t = s;
            replace_all(t, "\"", "\"\"");
            s = '\"';
            s += t;
            s += '\"';
        }
        record = s;
        for(size_t i = 1; i < values.size(); i++)
        {
            s = values[i];
            if (s.find(',') != -1 || s.find('\"') != -1 || s.find('\n') != -1)
            {
                t = s;
                replace_all(t, "\"", "\"\"");
                replace_all(t, "\r\n", "\n");
                s = '\"';
                s += t;
                s += '\"';
            }
            record += ',';
            record += s;
        }
    }
    record += "\r\n";
    fputs(record.c_str(), m_fp);
    return ferror(m_fp) == 0;
}

bool CsvWriter::WriteAll(const vector<vector<string> >& records)
{
    for(size_t i = 0; i < records.size(); i++)
    {
        if (!Write(records[i]))
            return false;
    }
    return true;
}

#ifdef UNITTEST
int main(void)
{
    CsvReader input;
    CsvWriter output;
    vector<vector<string> > records;
    if (input.Open("test1.csv"))
    {
        if (input.ReadAll(records))
        {
            for(size_t j = 0; j < records.size(); j++)
            {
                if (records[j].size() > 0)
                {
                    printf("%s", records[j][0].c_str());
                    for(size_t i = 1; i < records[j].size(); i++)
                    {
                        printf("<>%s", records[j][i].c_str());
                    }
                }
                printf("\n");
            }
        }
        input.Close();
    }

    if (output.Open("test2.csv"))
    {
        output.WriteAll(records);
        output.Close();
    }
    return 0;
}
#endif  /* def UNITTEST */

ソース: csv.zip


国内格安航空券サイトe航空券.com

戻る

©片山博文MZ
katayama.hirofumi.mz@gmail.com

inserted by FC2 system