Create .csv file in C++ in qt - c++

I want to create an csv file using c++, using Qt for application and UI framework. Is there's library for csv file.

Try qtcsv library for reading and writing csv-files. Example:
#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;
}
I tried to make it small and easy-to-use. See Readme file for library documentation and other code examples.

You could basically look into libqxt.
Using QxtCsvModel
The QxtCsvModel [libqxt.bitbucket.org] class provides a QAbstractTableModel [qt-project.org] for CSV Files. This is perhaps the easiest way possible to read and write csv files without having to parse the csv format to something qt can understand. It’s as simple as using one line of code, for example the following reads the csv file:
csvmodel->setSource(fileName);

Just writing CSV? Although google may reveal some CSV libraries, the probable reason why you have not found any is because it is so darn trivial. Remember CSV is just Comma Separated Values.
To implement it use any means to write a text file (std::ofstream, QFile, QTextStream) and do something along the lines of:
foreach record
{
foreach value in record
{
write "\"" + escape(value) + "\""
if not last value in record
{
write ","
}
}
write "\n"
}
escape (value)
{
replace each "\"" with "\"\""
}
Note that you can write the values without quotes if they do not contain any separators (,). Also note you can use different separators, for example the semi-colon is commonly used.

Related

Erase a word from a batch file which was added before [duplicate]

This question already has answers here:
Remove parts of text file C++
(4 answers)
Closed 3 years ago.
std::ofstream readd(startLoc, ios::out | ios::app);
readd << "/Uninstall";
readd.close();
this is for adding "/Uninstall" in batch file
now i want remove "/Uninstall" from the batch file which i have added using cpp(file handling append concept) in visual studio 2015 IDE
There are of course always many possible solutions, I will explain and show you one of them.
For the sake of some security to prevent data loss, we will NOT immediately work (modifiy) on the original source file. Instead, we will first open a temporary file, then read the source file, replace the searched word and then output the new data to the temporary file.
After all search and replace operations are finished, the original file will be deleted and the temporary file will be renamed to the original one.
For the search and replace functionality, I used in this example the std::regex_replace function. This is very flexible, because you can use regurlar expressions as search and replace strings. But this may be also a little bit difficult for beginners. Anyway, it will of course also replace normal strings as given by the user.
Please note: The proposed implementation does search and replace words, as requested by the OP. Deleting whole lines is not possible at the moment (an empty line will remain).
So, now the program flow.
Get a filename from the OS for the temporary file
Open a new scope, so that all open fstreams will be closed by the destructor automatically
Open the source file and check, if it could be opened. If not, issue error message
Open the temporary file and check, if it could be opened. If not, issue error message
Read the complete source file line by line
Search and replace string in this one line
Store result in temporary file
Delete the original source file
Rename the temporay file to the original
Additionally I added some error handling and status info.
Please see
#include <string>
#include <regex>
#include <vector>
#include <iostream>
#include <fstream>
#include <cstdio>
bool searchAndReplaceWordInFile(const std::string& filename, const std::string& searchString, const std::string& replaceString) {
// Get a temporary filename
#pragma warning(suppress : 4996)
const std::string tempFileName = std::tmpnam(nullptr);
// Result of file operations
bool result{ true };
// Open a new scope for the fstreams. The destructor will be called and the files will be closed
// after the fstreams will fall out of scope
{
// Open the source file name
std::ifstream sourceFile(filename);
// Check if it could be opened
if (sourceFile) {
// Open the temp file
std::ofstream tempFile(tempFileName);
// And check, if it could be opened
if (tempFile) {
// We will read the text file line by line
std::string textLine{};
// Read all lines of text file
while (std::getline(sourceFile, textLine)) {
// Serach, Replace, using regex and output in temp file
tempFile << std::regex_replace(textLine, std::regex(searchString), replaceString) << "\n";
}
}
else {
std::cerr << "*** Error Could not open temp file: " << tempFileName << "\n";
result = false;
}
}
else {
std::cerr << "*** Error Could not open source file: " << filename << "\n";
result = false;
}
}
if (result) {
// Remove original file and rename temp file to original file
std::remove(filename.c_str());
if (std::rename(tempFileName.c_str(), filename.c_str())) result = false;
}
return result;
}
int main() {
if (searchAndReplaceWordInFile("r:\\something.bat", "/Uninstall", ""))
std::cout << "Success, Done. \n";
return 0;
}

How to run a c++ program multiple times with different input files?

I'm new to C++ and writing my master thesis and would really appreciate any help I can get!
I have a program that reads a txt file, then does a bunch of calculations, and returns a new txt file. The thing is that I want to run this program for 100+ different input files. Now I have to change the name of the input file in the code, but I would like to have it run for all the input files in my folder by itself.
I am using Visual Studio, but with little C++ experience.
Thanks :)
See this snippet. Since you are using MSCV, you need to enable MFC in configuration for this console application. Also add #include "afx.h" in #include "stdafx.h" where CFileFind is defined. PopulateFromFolder() should auto load the files into the vector files.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
void PopulateFromFolder(string path, vector<string>& files)
{
CFileFind finder;
CString fileName;
fileName.Format(L"%s*.*", CString(path.c_str()));
BOOL bOk = finder.FindFile(fileName);
while (bOk)
{
bOk = finder.FindNextFile();
if (finder.IsDots())
{
continue;
}
if (!finder.IsDirectory())
{
CString strFileName = finder.GetFileName();
files.push_back(CStringA(strFileName).GetString());
}
}
finder.Close();
}
int main()
{
vector<string> files;
string path = "D:\\MyFolder\\";
PopulateFromFolder(path, files);
auto a = path + files[0];
int i = 0;
while (i< files.size()-1)
{
cout << "processing " << files[i + 1] << endl;
ifstream fs(path+files[i++]);
if (fs.is_open())
{
//do something
}
fs.close();
}
return 0;
}
Output:
Using bash you can run them using:
$ for file in /Data/*.txt; do /path/your_program $file; done
You can define format for your input files names and put then into some directory. For example,
Input1.txt
Input2.txt
...
Input111.txt
Then use some kind of for loop:
for(int i = 1; i <= 111; ++i)
{
ifstream file("Input" + std::to_string(i) + ".txt");
if (file.is_open())
Operate(file);
}
If you don't know the exact number of files, you can check whether the file was openen by is_open() method. This way files with some numbers can be absent. You just loop for some max possible input file id.
This was a solution which doesn't require any dependencies. But if you don't mind it, you actually may consider Boost.Filesystem. Here is an example.
You can try to use std::experimental::filesystem (http://en.cppreference.com/w/cpp/experimental/fs). I guess that directory_iterator from this library can be useful for you - it allows you to iterate over all files in a given directory. Have a look at the example provided in the documentation: http://en.cppreference.com/w/cpp/experimental/fs/directory_iterator.
However, you have to make sure that you are compiling your code with a new standard (C++ 17).
Another way is to make for example a separate file containing a list of the names of all files that you want to work on. Then, you can read this list and for every file do what you need.

New line seen in command prompt but the same string is seen with \n in file output

I have this code which runs fine
#include <iostream>
#include <set>
#include <sstream>
int main()
{
std::set<std::string> a;
a.insert("foo");
a.insert("bar");
a.insert("zoo");
a.insert("should");
a.insert("work");
std::stringstream b;
std::set<std::string>::iterator it;
for (it = a.begin(); it != a.end(); it++)
{
b << " " << *it <<"," <<"\n";
}
std::string aaa = b.str();
std::cout <<aaa;
}
Output in command prompt:
bar, //new line after ","
foo, //new line after ","
should,
work,
zoo,
If I try to write the same string aaa in file I am expecting the same output to get print in the file i.e. every string after "," in new line, rather I am getting output in my file as follows (In single line with \n):
" bar,\n foo,\n should,\n work,\n zoo,\n"
Can anyone help me with this?
More Information on writing the string in file:
Here's how I am writing into file:
boost::property_tree::ptree pt1;
pt1.put( "Output", aaa );
boost::property_tree::write_json( "result.json", pt1 );
This will write JSON file, output of the above code in (Windows - NotePad/NotePad++) is as below:
{
"Output": " bar,\n foo,\n should,\n work,\n zoo,\n"
}
You are not writing a normal file! You are using a JSON library to write a file for you. And as it happens, in JSON strings, the end-of-line character is escaped just like in C source files, that is as "\n".
So, summing up, that is the expected behavior. If you want to get normal end-of-line characters, write a normal file, with fopen() and friends.
This is expected behaviour.
You are passing the string (which contains newlines) to a JSON library for encoding into JSON. That encoding step includes converting newlines to the substring "\n", because that's how we represent newlines inside strings in JSON.
Read more about JSON on the json.org website.

Creating the same text file over and over

I need to create a program that writes a text file in the current folder, the text file always contains the same information, for example:
Hello,
This is an example of how the text file may look
some information over here
and here
and so on
So I was thinking in doing something like this:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ofstream myfile("myfile.txt");
myfile << "Hello," << endl;
myfile << "This is an example of how the text file may look" << endl;
myfile << "some information over here" << endl;
myfile << "and here" << endl;
myfile << "and so on";
myfile.close();
return 0;
}
Which works if the number of lines in my text file is small, the problem is that my text file has over 2000 lines, and I'm not willing to give the myfile << TEXT << endl; format to every line.
Is there a more effective way to create this text file?
Thanks.
If you have the problem of writing in same file, you need to use an append mode.
i.e., your file must be opened like this
ofstream myfile("ABC.txt",ios::app)
You may use Raw string in C++11:
const char* my_text =
R"(Hello,
This is an example of how the text file may look
some information over here
and here
and so on)";
int main()
{
std::ofstream myfile("myfile.txt");
myfile << my_text;
myfile.close();
return 0;
}
Live example
Alternatively, you may use some tools to create the array for you as xxd -i
If you don't care about the subtile differences between '\n' and std::endl, then you can create a static string with your text outside of your function, and then it's just :
myfile << str // Maybe << std::endl; too
If your text is really big, you can write a small script to format it, like changing every newlines with "\n", etc.
It sounds like you should really be using resource files. I won't copy and paste all of the information here, but there's a very good Q&A already on this website, over here: Embed Text File in a Resource in a native Windows Application
Alternatively, you could even stick the string in a header file then include that header file where it's needed:
(assuming no C++11 since if you do you could simply use Raw to make things a little easier but an answer for that has already been posted - no need to repeat).
#pragma once
#include <iostream>
std::string fileData =
"data line 1\r\n"
"data line 2\r\n"
"etc.\r\n"
;
Use std::wstring and prepend the strings with L if you need more complex characters.
All you need to do is to write a little script (or even just use Notepad++ if it's a one off) to replace backslashes with double backslash, replace double quotation marks with backslash double quotation marks, and replace line breaks with \r\n"{line break}{tab}". Tidy up the beginning and end, and you're done. Then just write the string to a file.

iterate over ini file on c++, probably using boost::property_tree::ptree?

My task is trivial - i just need to parse such file:
Apple = 1
Orange = 2
XYZ = 3950
But i do not know the set of available keys. I was parsing this file relatively easy using C#, let me demonstrate source code:
public static Dictionary<string, string> ReadParametersFromFile(string path)
{
string[] linesDirty = File.ReadAllLines(path);
string[] lines = linesDirty.Where(
str => !String.IsNullOrWhiteSpace(str) && !str.StartsWith("//")).ToArray();
var dict = lines.Select(s => s.Split(new char[] { '=' }))
.ToDictionary(s => s[0].Trim(), s => s[1].Trim());
return dict;
}
Now I just need to do the same thing using c++. I was thinking to use boost::property_tree::ptree however it seems I just can not iterate over ini file. It's easy to read ini file:
boost::property_tree::ptree pt;
boost::property_tree::ini_parser::read_ini(path, pt);
But it is not possible to iterate over it, refer to this question Boost program options - get all entries in section
The question is - what is the easiest way to write analog of C# code above on C++ ?
To answer your question directly: of course iterating a property tree is possible. In fact it's trivial:
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
int main()
{
using boost::property_tree::ptree;
ptree pt;
read_ini("input.txt", pt);
for (auto& section : pt)
{
std::cout << '[' << section.first << "]\n";
for (auto& key : section.second)
std::cout << key.first << "=" << key.second.get_value<std::string>() << "\n";
}
}
This results in output like:
[Cat1]
name1=100 #skipped
name2=200 \#not \\skipped
name3=dhfj dhjgfd
[Cat_2]
UsagePage=9
Usage=19
Offset=0x1204
[Cat_3]
UsagePage=12
Usage=39
Offset=0x12304
I've written a very full-featured Inifile parser using boost-spirit before:
Cross-platform way to get line number of an INI file where given option was found
It supports comments (single line and block), quotes, escapes etc.
(as a bonus, it optionally records the exact source locations of all the parsed elements, which was the subject of that question).
For your purpose, though, I think I'd recomment Boost Property Tree.
For the moment, I've simplified the problem a bit, leaving out the logic for comments (which looks broken to me anyway).
#include <map>
#include <fstream>
#include <iostream>
#include <string>
typedef std::pair<std::string, std::string> entry;
// This isn't officially allowed (it's an overload, not a specialization) but is
// fine with every compiler of which I'm aware.
namespace std {
std::istream &operator>>(std::istream &is, entry &d) {
std::getline(is, d.first, '=');
std::getline(is, d.second);
return is;
}
}
int main() {
// open an input file.
std::ifstream in("myfile.ini");
// read the file into our map:
std::map<std::string, std::string> dict((std::istream_iterator<entry>(in)),
std::istream_iterator<entry>());
// Show what we read:
for (entry const &e : dict)
std::cout << "Key: " << e.first << "\tvalue: " << e.second << "\n";
}
Personally, I think I'd write the comment skipping as a filtering stream buffer, but for those unfamiliar with the C++ standard library, it's open to argument that would be a somewhat roundabout solution. Another possibility would be a comment_iterator that skips the remainder of a line, starting from a designated comment delimiter. I don't like that as well, but it's probably simpler in some ways.
Note that the only code we really write here is to read one, single entry from the file into a pair. The istream_iterator handles pretty much everything from there. As such, there's little real point in writing a direct analog of your function -- we just initialize the map from the iterators, and we're done.