I'm writing a function which reads a CSV file using getline() and converts data to the vector of vectors. To test it I've tried to read two files with the same delimiter: one imported from the internet and second exported from R datasets. The first few lines of each looks like:
File1.csv
User ID,Category 1,Category 2,Category 3,Category 4,Category 5,Category 6,Category 7,Category 8,Category 9,Category 10
User 1,0.93,1.8,2.29,0.62,0.8,2.42,3.19,2.79,1.82,2.42
User 2,1.02,2.2,2.66,0.64,1.42,3.18,3.21,2.63,1.86,2.32
User 3,1.22,0.8,0.54,0.53,0.24,1.54,3.18,2.8,1.31,2.5
User 4,0.45,1.8,0.29,0.57,0.46,1.52,3.18,2.96,1.57,2.86
File2.csv
"","Sepal.Length","Sepal.Width","Petal.Length","Petal.Width"
"1",5.1,3.5,1.4,0.2
"2",4.9,3,1.4,0.2
"3",4.7,3.2,1.3,0.2
"4",4.6,3.1,1.5,0.2
However getline() works only for the first one. In second case it simply returns white space. The function performs similar even if I copy single lines from one file to another (of course adding or removing additional colums) -- the rows from file1 will be always properly read while those from file2 never. I've even tried removing " chars, but without much improvement. However switching from comas to '\t' solves the problem.
I'm curious what's the difference between those two files that makes such different outcome?
The source code of my function:
vector<vector<string>> readData(string fileName,int firstLine,char delimeter){
//Open data file
fstream fin;
fin.open(fileName, ios::in);
//Data stored in 2d vector of strings
vector<vector<string>> data;
vector<string> row;
string line,word,temp;
//Read data
int i=0;
while(fin>>temp){
row.clear();
//Read line and store in 'line'
getline(fin,line);
//Don't read first n lines
if (i<firstLine){
i++;
continue;
}
cout<<line<<endl;
//Break words
stringstream s(line);
//Read every column and store in in 'word;
while(getline(s,word,delimeter)){
row.push_back(word);
}
//Append row to the data vector
data.push_back(row);
}
//Close file
fin.close();
return data;
}
The problem is here:
while(fin>>temp){
row.clear();
//Read line and store in 'line'
getline(fin,line);
fin >> temp reads everything till the first space or newline. It is not clear why you do that as only with getline(fin,line) you then try to read the full line and you are not using temp. In the first file fin>>temp consumes only "User", in the second file it consumes the full line, because there are no spaces.
If you look at the read data from the first file you will also notice that the first part of each line is missing.
Tip: Use more meaningful names for your variables. I didn't manage to fully understand your logic, because variables named s and the presence of row and line at the same time causes me headaces.
I have a file of 10 rows, I want to do a specific thing that is not important in this context. After reaching the end of a line, the program crash with the error in the title.
I went in the line of the header file it's referring:
{ Q_ASSERT(uint(i) < uint(size())); return QChar(d->data()[i]); }
but still I don't understand. This is my block of code:
QFile file("file.txt");
QTextStream in(&file);
QString s;
int i = 0;
while(!in.readLine().at(i).isNull()) {
s = s + in.readLine().at(i);
++i;
}
EDIT: What I'm trying to do is copy in the QString variable "s" a line of a file character by character.
It means that i is not a valid index for whatever is being returned from readLine(). In other words i is bigger than the length of the line.
The logic in the loop is really curious. I'm sure it's not doing what you think it's doing.
I think what you are trying to write is something like this
QFile file("file.txt");
QTextStream in(&file);
QString s;
QString line = in.readLine();
int i = 0;
while (!line.at(i).isNull()) {
s = s + line.at(i);
++i;
}
That code just reads one line, your code reads multiple lines.
I see two issues (unless I misunderstand how at() and readLine() work):
1) In the while() statement you are reading in a line with ...in.readLine()..., but then in the loop you read in again with another ...in.readLine().... So at the start of the first iteration you read in a line, and then as the body of the loop executes you read in a line again.
2) For every iteration of while you are incrementing i and grabbing that character from in. So for the first iteration (i=0) you grab the 0th character, for the second (i=1) you grab the 1st character.... and so on.
I would like to append entries in a simple csv file at the second line. The first line contains my column headers and the newest entry has to be on top.
My thought is to read in the first line until the '\n', then move to the next line and write there, but i don't know if that is the most efficient solution. Can someone provide an example?
Since you have stated in the comments that this file will not be very large I would suggest you read in the header into some sort of container. Then insert after the header the newest data that needs to be inserted into the file. Then read in the rest of the file. After you do that then you can write the contents of the container back into the file. Here is a simple demonstration:
std::ifstream fin("somefilename");
std::vector<std::string> file;
file.reserve(30); // grow the capacity to save on allocations
std::string reader;
std::string new_data = "some new data";
getline(fin, reader);
file.push_back(reader); //add header
file.push_back(new_data); // add new line
while(getline(fin, reader)) // get rest of file
file.push_back(reader);
std::ofstream fout("somefilename");
for (const auto & e : file)
fout << e << "\n";
I am new to file-handling...
I am writing a program that saves data in text-files in the following format:
3740541120991
Syed Waqas Ali
Rawalpindi
Lahore
12-12-2012
23:24
1
1
(Sorry for the bad alignment, it's NOT a part of the program)
Now I'm writing a delete function for the program that would delete a record.
So far this is my code:
void masterSystem::cancelReservation()
{
string line;
string searchfor = "3740541120991";
int i=0;
ifstream myfile("records.txt");
while (getline(myfile, line))
{
cout << line << endl;
if (line==searchfor)
{
// DELETE THIS + THE NEXT 8 LINES
}
}
}
I've done a bit of research and have found out that there is no easy way to access the line of a text file so we have to create another text file.
But the problem arises that how do I COPY the records/data before the record being deleted into the NEW text file?
Open the input file; read one line at a time from the input file. If you decide to want to keep that line, write it to the output file. On the other hand, if you want to 'delete' that line, don't write it to the output file.
You could have a record per line and make even more easy for example:
3740541120991|Syed Waqas Ali|Rawalpindi|Lahore|12-12-2012|23:24|1|1
and the | character saparating each field. This is a well known technic knows as CSV (Comma separated Values)
This way you don't have to worry about reading consecutive lines for erase a record and add a record access the file only once.
So your code becoms into:
void masterSystem::cancelReservation()
{
string line;
string searchfor = "3740541120991";
ifstream myfile("records.txt");
while (getline(myfile, line))
{
// Here each line is a record
// You only hace to decide if you will copy
// this line to the ouput file or not.
}
}
Don't think only about removing a record, there are others operations you will need to do against this file save a new record, read into memory and search.
Think a moment about search, and having your current desing in mind, try to answer this: How many reservations exists for date 12-12-2012 and past 12:00 AM?
In your code you have to access the file 8 times per record even if the other data is irrelevant to the question. But, if you have each record in a line you only have to access file 1 time per record.
With a few reservations the diference is near 0, but it grows exponentially (n^8).
I have a "sequence.dat" file that contains "1"s and "-1"s in a vertical representation (i.e.: each element is in a single line).. I am trying to read the file as follow:
QFile sequence("Sequences.dat");
sequence.open(QIODevice::ReadOnly);
QByteArray data = sequence.readAll();
for(int i=0; i<29; i++){
signedNo[i] = data[i]; // debugging breaking point
}
sequence.close();
however, at the debugging breaking point, the QByteArray "data" contains "1, -, 1, \n" instead of "1,-1" ...
is there is away to read the whole line at once and not each byte individually ? and ...
if there is not, how to tell the "readAll" function to avoid the "\n" (it is not an optimal solution because I want also to read "-1" and not "- and 1" separately)
QFile::readAll() returns a byte array which contains each and every byte of the file as a separate element.
For your use case, you need to read the file line by line.
The QFile documentation shows some approaches how to do this, for example:
QVector<int> elements;
QFile sequence("Sequences.dat");
if (!sequence.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&sequence);
while (!in.atEnd()) {
QString line = in.readLine();
elements.append(line.toInt());
}
Despite the fact that this sample is from the Qt documentation, I would recommend to check the return value from in.readLine() which returns a null QString when the end of the file has been reached, instead of using atEnd().
You could read line by line, and you could process it right after you read the line:
i = 0;
while (!sequence.atEnd()) {
QByteArray line = sequence.readLine();
signedNo[i] = line[i];
i++;
}