How to delete a line from a txt file in Qt? - c++

My txt file (CopyBook.txt) contains for example 10 lines. I want to delete the third one.
I have this code:
QString fname = "C://Users//Tomahawk//Desktop//copy//CopyBook.txt";
QFile file(fname);
if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
{
QTextStream edit(&file);
QString line;
int reachForLine = 0;
int neededLine = 3;
while (reachForPage != pageCounter)
{
line = edit.readLine();
reachForPage++;
}
}
So you can see I use "while" to reach for the line i want to delete. But I haven't found any method in Qt that allows me to do it. In future I want to use the ability of deleting lines to replace them with another ones. So how do I delete it?

One way to do it would be to read all of the lines into a QStringList, modify the QStringList, and then turn around and write its contents back to the file again, like this:
int main(int argc, char ** argv)
{
const QString fname = "C:/Users/Tomahawk/Desktop/copy/CopyBook.txt";
QStringList lines;
// Read lines of text from the file into the QStringList
{
QFile inputFile(fname);
if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream edit(&inputFile);
while (!edit.atEnd()) lines.push_back(edit.readLine());
}
inputFile.close();
}
// Delete the third line from the QStringList
if (lines.length() > 2) lines.removeAt(2); // 0==first line, 1==second line, etc
// Write the text in the QStringList back to the file
{
QFile outputFile(fname);
if (outputFile.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream edit(&outputFile);
for (int i=0; i<lines.size(); i++) edit << lines[i] << Qt::endl;
}
outputFile.close();
}
return 0;
}
You could also perform any replacements/insertions you want to make on the QStringList object, before writing it back to the file.
Note that this approach does use up RAM proportional to the size of the file, so for very large files (e.g. gigabytes long) you would probably want to use the create-a-second-file-and-then-rename approach proposed by #TedLyngmo in his comment, instead. For small files, OTOH, buffering in RAM is somewhat easier and less error-prone.

Related

Qt - How to save and load a QVector<QString> into multiple labels?

So I have multiple labels full of text, and I would like to save all of these labels in one go into a QVector<QString>. The Below code is what I have tried and it works but nothing is ever loaded when I load the saved file, I have checked the saved file with notepad and there is stuff in there, so maybe the load option is not working correctly? I'm not sure but help is appreciated. I also ask if you can suggest a better way of doing this if this seems like a bad or horribly inefficient way, again thanks for the help in advance.
The code for saving:
void Tasks::on_pushButton_5_clicked()
{
const int length = 10;
QVector<QString> AllTasks(length);
AllTasks<<ui->label->text()<<ui->label_2->text()<<ui->label_3->text()<<ui->label_4->text()<<
ui->label_5->text()<<ui->label_6->text()<<ui->label_10->text()<<ui->label_11->text()<<
ui->label_12->text()<<ui->label_13->text();
QString fileName = QFileDialog::getSaveFileName(this,tr("Save All Tasks"),"", tr("Tasks(*.tsk);;All Files (*)"));
QFile file(fileName);
if(file.open(QIODevice::WriteOnly)){
QDataStream stream(&file);
stream<<AllTasks;
}
file.close();
}
and the code for loading:
void Tasks::on_pushButton_6_clicked()
{
const int length = 10;
QVector<QString> AllTasks(length);
AllTasks<<ui->label->text()<<ui->label_2->text()<<ui->label_3->text()<<ui->label_4->text()<<
ui->label_5->text()<<ui->label_6->text()<<ui->label_10->text()<<ui->label_11->text()<<
ui->label_12->text()<<ui->label_13->text();
QString fileName = QFileDialog::getOpenFileName(this,tr("Save Tasks"),"", tr("Task(*.tsk);;All Files (*)"));
QFile file(fileName);
if(file.open(QIODevice::ReadOnly)){
QDataStream stream(&file);
stream.setVersion(QDataStream::Qt_4_8);
stream>>AllTasks;
}
file.close();
}
You do this for saving:
AllTasks<<ui->label->text()<<ui->label_2->text()<<ui->label_3->text()<<ui->label_4->text()<<
ui->label_5->text()<<ui->label_6->text()<<ui->label_10->text()<<ui->label_11->text()<<
ui->label_12->text()<<ui->label_13->text();
and you do the same for loading. Why? The "data flows" in the direction of the operator (<< - into the AllTasks). This code does not create a special elements referencing the text objects of your labels.
It does exactly what it does for saving the data to a file. It fills up the AllTasks. Then, you fill it up even more with the data read from the file.
Solution: Change << to >> and move the whole statement to be executed after you're done with reading the file.
Edit: There's no operator>>. Either do:
ui->label->setText(AllTasks.at(0));
ui->label_2->setText(AllTasks.at(1));
...
ui->label_13->setText(AllTasks.at(12));
or:
QVector<QLabel*> labels << ui->label << ui->label_2 << ... << ui->label_13;
for(int i = 0; i < labels.size() && i < AllTasks.size(); ++i)
labels[i]->setText(AllTasks[i]);

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

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

Reading a txt file using QTextStream C++

I am making a small program I have done before in Java however I want to try and get the same working in C++. The idea is to merge two text files
file1:
a
b
c
file2:
1
2
3
output file should read:
a1
b2
c3
I have looked at the QTextStream docs and this was the suggested code to read a file by line into strings
QFile file(input); // this is a name of a file text1.txt sent from main method
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
return 1;
}
QTextStream in(&file);
QString line = in.readLine();
while (!line.isNull())
{
line = in.readLine();
}
Yet for some reason nothing is being loaded from the file at all. I proved this by printing 'line' to console and got nothing.
So any ideas? All I want is to read the file and end up with a string like this
QString text1 = "a\n2\n3"
I'd do this for both files, split the strings into QStringList (most likely) join them together in the format I want and write them to a 3rd txt file.
Why do you read line by line if you want the entire file?
QString line = in.readAll();
ALso, your while loop is wrong, you need to while (!in.atEnd()) for the text stream instead of checking if the string is null.
readLine won't include the new line symbol.
Anyway, it would be much easier to open both files at the same time and construct your string on the go instead of splitting and joining.
QFile f1("h:/1.txt");
QFile f2("h:/2.txt");
f1.open(QIODevice::ReadOnly | QIODevice::Text);
f2.open(QIODevice::ReadOnly | QIODevice::Text);
QString s;
QTextStream s1(&f1);
QTextStream s2(&f2);
for (int i = 0; i < 3; ++i) {
s.append(s1.readLine());
s.append(s2.readLine());
if (i != 2)s.append("\n");
}
If the file name does not contain full path, but you are very sure that the file is located in the same directory as your application, use the applications path like this:
QString filename = QCoreApplication::applicationDirPath() + "/" + input;
Try this block-:
while(!in.atEnd())
{
QString line = in.readLine();
....
}
do you get output using this while loop?

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.

Reading text file in Qt

I want to read a huge text file in which I will be dividing the strings according to the comma (,) and store the strings in the array. So how to do this. Is there any class which does the action as StringTokenizer as in badaOS. I have tried QFile but it is not able to read whole file.
QTextStream lets you read line by line
QFile file(hugeFile);
QStringList strings;
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream in(&file);
while (!in.atEnd()) {
strings += in.readLine().split(";");
}
}
You can use file streams.
QFile file = new QFile(hugeFile);
file.open(QIODevice.OpenModeFlag.ReadOnly);
QDataStream inputStream = new QDataStream(file);
QStringList array;
QString temp;
while(!inputStream.atEnd()) {
inputStream >> temp;
array << temp.split(";");
}
Note that this is untested (pseudo) code, hope it helps.
You can always read a part of file:
QFile file( ... );
file.read(1000); // reads no more than 1000 bytes
Or you car read Your file line by line:
file.readLine();
but You'll have to handle cases when one string was splitted in two pieces.
If it's a really huge file then you can read with the file.read(an_appropriate_number) while file.atEnd() is false.
Read a chunk (with file.read()), add it to a temporary string buffer and search for a ',' (e.g. with QString's contains() method). If it contains a ',' then split it (with QString's split() method): the first X parts (the read 1000 characters may contain more than 1 tokens) will contain the found tokens and the last one is not a complete token yet. So switch the temporary string to the last part of the split and read another chunk (until you hit file.atEnd()) and append it to the temporary string buffer. This will work efficiently unless your tokens are huge. And don't forget to handle the last buffered text after you hit file.atEnd() :)
Or as an alternative you can read the file character-by-character and check for ',' manually, but it's always better to read more than 1 character (it's more efficient if you read more).
This won't capture whitespace after a comma. If that's not acceptable, feel free to optimize the regex. You can probably also reduce the amount of includes at the top. I was just being thorough. I tested this on a 1600 line file, and it seemed to handle it well in Qt 5.6
#include <QCoreApplication>
#include <QFile>
#include <QIODevice>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QRegularExpressionMatchIterator>
#include <QString>
#include <QStringList>
#include <QTextStream>
int main(int argc, char * argv[])
{
QCoreApplication app(argc, argv);
QFile file("C:\\PathToFile\\bigFile.fileExt");
QStringList lines;
QStringList matches;
QString match;
file.open(QIODevice::ReadOnly | QIODevice::Text);
while(!file.atEnd())
{
lines << file.readLine();
}
file.close();
QRegularExpression regex("(^|\\s|,)\\K\\w.*?(?=(,|$))");
QRegularExpressionMatchIterator it;
foreach (QString element, lines)
{
it = regex.globalMatch(element);
while(it.hasNext())
{
QRegularExpressionMatch qre_match = it.next();
match = qre_match.captured(0);
matches << match;
}
}
return 0;
}