Small easy-to-use library for reading and writing csv-files in Qt.
Tested on:
- Ubuntu 14.04 with gcc 4.8.4, Qt 4.8 and higher
- Windows with MinGW, Qt 5.3 and higher
- OS X with clang, Qt 4.8, 5.5, 5.7 and higher
#include <QList>
#include <QStringList>
#include <QDir>
#include <QDebug>
#include "qtcsv/stringdata.h"
#include "qtcsv/reader.h"
#include "qtcsv/writer.h"
int main()
{
// prepare data that you want to save to csv-file
QStringList strList;
strList << "one" << "two" << "three";
QtCSV::StringData strData;
strData.addRow(strList);
strData.addEmptyRow();
strData << strList << "this is the last row";
// write to file
QString filePath = QDir::currentPath() + "/test.csv";
QtCSV::Writer::write(filePath, strData);
// read data from file
QList<QStringList> readData = QtCSV::Reader::readToList(filePath);
for ( int i = 0; i < readData.size(); ++i )
{
qDebug() << readData.at(i).join(",");
}
return 0;
}
There are three main classes: Reader, Writer and AbstractData.
AbstractData is a pure abstract class that provide interface for a container class. Here is how it looks:
class AbstractData
{
public:
explicit AbstractData() {}
virtual ~AbstractData() {}
virtual void addEmptyRow() = 0;
virtual void addRow(const QStringList& values) = 0;
virtual void clear() = 0;
virtual bool isEmpty() const = 0;
virtual int rowCount() const = 0;
virtual QStringList rowValues(const int& row) const = 0;
};
As you can see, AbstractData declare virtual functions for adding new rows, getting rows values, clearing all information and so on. Basic stuff for a container class.
If you have said Pure Abstract Class, you must also say Implementation. Don't worry, we have some:
StringData have the same interface as AbstractData (plus some useful functions for inserting rows, removing rows and so on) and stores all data as strings. It's useful when information that you want to save in csv-file is represented as strings.
If you store information in different types - integers, floating point values, strings or (almost) anything else (example: [1, 3.14, "check"]) - and you don't want to manually transform each element to string, then you can use QVariant magic. Wrap your data into QVariants and pass it to VariantData class.
Use Reader class to read csv-files. It's very simple. It has only two functions:
- Read data to QList<QStringList>
QList<QStringList> readToList(const QString& filePath,
const QString& separator,
const QString& textDelimiter,
QTextCodec* codec);
- filePath - string with absolute path to existent csv-file (example: "/home/user/my-file.csv");
- separator (optional) - delimiter symbol, that separate elements in a row (by default it is comma - ",");
- textDelimiter (optional) - text delimiter symbol that enclose each element in a row (by default it is double quoute - ");
- codec (optional) - pointer to the codec object that will be used to read data from the file (by default it is UTF-8 codec).
As a result function will return QList<QStringList> that holds content of the file. If all went smooth, list will not be empty and size of it will be equal to the number of rows in csv-file. Each QStringList will contain elements of the corresponding row.
- Read data to AbstractData-based container
bool readToData(const QString& filePath,
AbstractData& data,
const QString& separator,
const QString& textDelimiter,
QTextCodec* codec);
Second function is a little more advanced and, I hope, a little more useful.
- filePath - string with absolute path to existent csv-file;
- data - reference to AbstractData-based class object;
- separator (optional) - delimiter symbol;
- textDelimiter (optional) - text delimiter symbol;
- codec (optional) - pointer to the codec object.
Function will save content of the file in data object, using virtual function AbstractData::addRow(QStringList). If you pass to the function Reader::readToData() object of class StringData or VariantData, elements of csv-file will be saved in them as strings.
If you are not happy with this fact, you can create your own AbstractData-based container class and implement function addRow(QStringList) in a way you want it.
For example, if you know, that each row of your csv-file contains 3 elements (integer value, floating-point value and string), then in function addRow(QStringList) you can convert first element of QStringList to int, second - to double and save all three elements to some internal container (or do with them whatever you want).
Use Writer class to write to csv-files. It has only one function:
bool Writer::write(const QString& filePath,
const AbstractData& data,
const QString& separator,
const QString& textDelimiter,
const WriteMode& mode,
const QStringList& header,
const QStringList& footer,
QTextCodec* codec)
- filePath - string with absolute path to csv-file (new or existent);
- data - object, that contains information that you want to write to csv-file. Writer internally will use QStringList AbstractData::rowValues(int) function to get row values;
- separator (optional) - delimiter symbol (by default it is comma - ",");
- textDelimiter (optional) - text delimiter symbol that enclose each element in a row (by default it is double quoute - ");
- mode (optional) - write mode flag. If it set to WriteMode::REWRITE and csv-file exist, then csv-file will be rewritten. If mode set to WriteMode::APPEND and csv-file exist, then new information will be appended to the end of the file. By default mode set to WriteMode::REWRITE.
- header (optional) - strings that will be written at the beginning of the file, separated with defined separator (empty by default);
- footer (optional) - strings that will be written at the end of the file, separated with defined separator (empty by default);
- codec (optional) - pointer to the codec object that will be used to write data to the file (by default it is UTF-8 codec).
Writer uses CRLF as line ending symbols in accordance with standard. If element of the row contains separator symbol or line ending symbols, such element will be enclosed by text delimiter symbols (or double quoute if you have set empty string as text delimiter symbol).
Qt 4.8 and higher. It is quite possible, that library will be successfully built with older Qt versions (4.7, 4.6, ...).
If you going to build qtcsv library on Windows, first of all check that your PATH variable contains paths to Qt and MinGW toolsets. For example, you have installed Qt 5.3 into C:\Qt. Then Qt binaries and libraries will be in folder C:\Qt\5.3\mingw482_32\bin and MinGW binaries will be in C:\Qt\Tools\mingw482_32\bin. Add these paths to the PATH variable so that Windows would know where to look for qmake and make binaries.
cd /path/to/folder/with/qtcsv
# Build library
qmake
make
# Build tests
cd ./tests
qmake
make
If you want to run tests, then use this commands after build of qtcsv:
cd /path/to/folder/with/qtcsv
chmod 777 qtcsv_tests
./qtcsv_tests
cd /path/to/folder/with/qtcsv
qtcsv_tests.exe
On Unix-like OS you can install qtcsv library using this command:
sudo make install
sudo ldconfig -n -v /usr/local/lib
This command will copy all compiled files (libqtcsv.so*) from "./src" folder to "/usr/local/lib". Also all headers files will be copied from "./src/include" folder to "/usr/local/include/qtcsv".
All installation settings are defined in qtcsv.pro file. See libheaders and target variables.
For additional information, see Qt documentation about files installation.
If you want to try qtcsv, you can download qtcsv-example project. Don't forget to read README file!
If you want to know more about csv-file format, read RFC 4180 standard.
Also on this page you can find useful tips about how should look proper csv-file.
Author: Antony Cherepanov (antony.cherepanov@gmail.com)
Contributors: Patrizio "pbek" Bekerle, Furkan "Furkanzmc" Üzümcü, Martin "schulmar" Schulze