How to avoid reading "\n" when using QFile::readAll function - c++

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++;
}

Related

QT: ASSERT: "uint(i) < uint(size())" in file C:\Qt\Qt5.14.2\5.14.2\mingw73_64\include/QtCore/qstring.h, line 1029

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.

QT, Write in new line in a file

I have written a code to read from line_Edit in GUI, and write in a file. The code reads the text from line edit and writes the same in the file, but they are printed continuously without any spaces, I want to print the texts written in the line edit in different lines. The file has written text, just want to replace first word of each line by the user entered words.
Code to write in the file:
void MainWindow::on_write_btn_clicked(){
QString str, str2, lin;
str = ui->lineEdit->text();
str2 = ui->lineEdit2->text();
QFile file1("sample.txt");
if(file1.open(QIODevice::ReadWrite | QIODevice::Text)){
QTextStream out(&file1);
out << str;
lin = out.readLine();
out << str2;
file1.seek(30);
file1.close();
}
else
return;
}
File in which we want to write:
If you want the next string to be in a new line in the file you should add the new line character(s) to the stream \n.
Referring to your code you should put:
out << str << '\n' << str2;
which would make the contents of str and str2 appear in consecutive lines.
Instead of the above you could also use the endl manipulator from QTextStream:
out << str << endl << str2;
For this to work properly you need to be opening the file with QIODevice::Text and assure that the endl you are specifying actually comes from QTextStream (not std)
Also note that since you probably only want to write your file there is no need in opening it with ReadWrite option, WriteOnly should be enough.
EDIT according to further details:
To substitute first word from each line of the file you could do the following. Open two files, one which will be read and the second to write the modified data. After iterating though all the lines close the files, remove the original one and rename the output file to replace the original one. Sample implementation:
QFile fileIn("textIn.txt"), fileOut("textOut.txt");
fileIn.open(QFile::ReadOnly); // check result
fileOut.open(QFile::WriteOnly); // check result
QTextStream streamIn(&fileIn), streamOut(&fileOut);
const QChar delimeter = ' ';
while (!streamIn.atEnd())
{
QStringList list = streamIn.readLine().split(delimeter);
if (list.size() > 0) // in case of empty line
list[0] = "substitutedText"; // here put the text you want to set
streamOut << list.join(delimeter) << "\r\n"; // or endl
}
fileIn.close();
fileOut.close();
fileIn.remove(); // check result
fileOut.rename(QFileInfo(fileIn).absoluteFilePath()); // check result
Of course you could try doing the replacement on the original file opened with ReadWrite modifier and setting proper position inside the stream using seek. Although it could get tricky due to different lengths of the read and written data.

QTextStream Comparing first character of each line in a csv file with a known variable?

Title pretty much says it all, but I better be a little more specific so as not to confuse any one(including myself).
Been at this for two days not much success.
I have a CSV file and open/read it line by line with QTextStream. The line length is set to first character of each line only, line.at(0). It compares the beginning of each line with a know variable/integer.
It works and the label does show "Match Found" but immediately afterwards, the app crashes. It never reaches the"No Matches Found".
The error I'm getting:
ASSERT: "uint(i) < uint(size())" in file ..\..\..\..\Qt\5.0.2\mingw47_32\include/QtCore/qstring.h, line 729
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
Any ideas? Anyone?
Oh yeah, here is the code to the function causing this headache.
void DialogToll::ReadAndCompare()
{
QString Number = ui->Tolls->text();
QFile filetoCompare("C:/Tolls.txt");
if(filetoCompare.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream stream(&filetoCompare);
QString line;
do
{
line = stream.readLine();
if(line.at(0)== Number)
{
ui->label->setText("match Found!!!");
}
}while(!line.isNull());
ui->label->setText("No match Found!");
}
}
You read file line by line, but it looks like some of the lines have zero length, so that your line.at(0) fails. I would improve your code in the following way:
[..]
QTextStream stream(&filetoCompare);
do
{
QString line = stream.readLine();
if (line.size() > 0 && line.at(0) == Number)
{
ui->label->setText("match Found!!!");
}
} while (!line.isNull());
ui->label->setText("No match Found!");
[..]
Note that I check for the line's length before comparing its first character.
Like #Vahancho said: you're not checking your line before accessing it's elements. This will cause a crash for empty lines.
Did you realize that you overwrite the ui label after the loop
finished? You can prevent that by returning early:
Next, you may want to use the power of QRegexp for this:
void checkMatch() {
....
QRegexp expr("^"+ui->Tolls.text());
do {
auto line = stream.readLine();
if (expr.exactMatch(line)) {
ui->label->setText("Match");
return; // <<<< early return
}
} while(!stream.atEnd());
ui->label->setText("no match");
}

Working with files in Qt

Let's say I write some information in a file, and it writes with n cycles, for example as follows:
a,a,a,a,
b,b,b,b,
c,c,c,c,
a,a,a,a,
b,b,b,b,
c,c,c,c,
.......
a,a,a,a,
b,b,b,b,
c,c,c,c,
Now I want to open the file check the first line, find where it repeats and delete everything after that. For my example case let's say I want to wind where a,a,a,a, meets again, and to delete it, and everything after that, getting the follows instead:
a,a,a,a,
b,b,b,b,
c,c,c,c,
Q: How can I do that?
You can use QTextStream to stream your file (so, do not care about RAM).
Then use readLine() function to read one line at a time to QString, and compare with new line.
Here some code sample:
int lineCounter = 0; //count for line
QFile f(filePath);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
QTextStream stream(&f);
QString line;
// read the first line
line = stream.readLine();
lineCounter++;
QString hash = QString(QCryptographicHash::hash(line.toAscii(), QCryptographicHash::Md5).toHex());
do
{
line = stream.readLine();
if (QString(QCryptographicHash::hash(line.toAscii(), QCryptographicHash::Md5).toHex()).compare(hash) == 0)
{
// Save data from 1st line to "lineCounter" to new file, or do your own works;
// and then break;
}
lineCounter++;
} while (!line.isNull());
You want to remove duplicate lines in a file. If you follow the next steps you will get what you want.
Create a vector that will store the hashes of unique lines ( QVector<QString>) Notice that using QMap would be faster.
Create an ouput file
For every line in the file calculate it's hash. Use QCryptographicHash or qHash (in this case you should have a vector of uints.
If the calculated hash is contained in the vector skip this line
Otherwise add the hash to the vector and print the line to the output file.
At the end the output file should contain only unique instances of the input file.

Qt, QFile write on specific line

I've run into another problem in Qt, I can't seem to figure out how to write on a specific line on a text file with QFile. Instead, everything is erased written at the beginning.
So with the given information, how would I write to a specific line in QFile?
Here are two functions.
The first function searches a file, and then gets two variables. One that finds the next empty line, one that gets the current ID number.
Second function is supposed to write. But I've looked for documentation on what I need, I've googled it and tried many searches to no avail.
Function 1
QString fileName = "C:\\Users\\Gabe\\SeniorProj\\Students.txt";
QFile mFile(fileName);
QTextStream stream(&mFile);
QString line;
int x = 1; //this counts how many lines there are inside the text file
QString currentID;
if(!mFile.open(QFile::ReadOnly | QFile::Text)){
qDebug() << "Could not open file for reading";
return;
}
do {
line = stream.readLine();
QStringList parts = line.split(";", QString::KeepEmptyParts);
if (parts.length() == 3) {
QString id = parts[0];
QString firstName = parts[1];
QString lastName = parts[2];
x++; //this counts how many lines there are inside the text file
currentID = parts[0];//current ID number
}
}while (!line.isNull());
mFile.flush();
mFile.close();
Write(x, currentID); //calls function to operate on file
}
The function above reads the file, which looks like this.
1001;James;Bark
1002;Jeremy;Parker
1003;Seinfeld;Parker
1004;Sigfried;FonStein
1005;Rabbun;Hassan
1006;Jenniffer;Jones
1007;Agent;Smith
1008;Mister;Anderson
And the function gets two bits of information that I figured I might need. I'm not too familiar with QFile and searching, but I thought that I'd need these variables:
int x; //This becomes 9 at the end of the search.
QString currentID; //This becomes 1008 at the end of the search.
So I passed in those variables to the next function, at the end of function 1. Write(x, currentID);
Function 2
void StudentAddClass::Write(int currentLine, QString idNum){
QString fileName = "C:\\Users\\Gabe\\SeniorProj\\Students.txt";
QFile mFile(fileName);
QTextStream stream(&mFile);
QString line;
if(!mFile.open(QFile::WriteOnly | QFile::Text)){
qDebug() << "Could not open file for writing";
return;
}
QTextStream out(&mFile);
out << "HelloWorld";
}
I've left out any attempts at fixing the problem myself, all this function does is replace all the contents of the text file with "HelloWorld".
Does anyone know how to write on a specific line, or at least go to the end of the file and then write?
If the line you want to insert into the file is always the last line (as the function 1 suggest) you can try to open the file in append mode using QIODevice::Append in your Write method.
If you want to insert a line in the middle of the file, I suppose an easy way is to use a temp file (or, if it is possible, to load the lines into a QList, insert the line and write the list back to the file)
QString fileName = "student.txt";
QFile mFile(fileName);
if(!mFile.open(QFile::Append | QFile::Text)){
qDebug() << "Could not open file for writing";
return 0;
}
QTextStream out(&mFile);
out << "The magic number is: " << 4 << "\n";
mFile.close();
The above code snippet will append the text "The magic number is: 4" , at the end of the file.