Overwrite text file vs append - qt

I'm looking to overwrite data in a text file but all I can seem to do is append to it
mFile.open(QFile::ReadWrite)
QTextStream in(&mFile);
QString first = in.readLine(); //discard the headers
QString dataLine = in.readLine(); //headers
QStringList sql_row = dataLine.split("\t"); //first row (sake of proj only 1 row)
if(sql_row[1].isEmpty()) //no user name registered
{
QByteArray user= getenv("USERNAME"); //for windows
if(user.isEmpty())
{
user = getenv("USER"); ///for MAc or Linux
}
dataLine = dataLine.insert(dataLine.indexOf("\t")+ 1,user);
in << first << endl << dataLine << endl;
mFile.flush();
mFile.close();

Change
mFile.open(QFile::ReadWrite);
to
mFile.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text);
The QIODevice vs QFile distinction isn't necessary, but I personally favor using the base class. The Truncate flag will overwrite (i.e., delete) an existing file.
Alternatively, you can follow the other suggestion and open your text file directly using one of QTextStream's constructors. The same QIODevice::OpenMode conventions apply. This only works if mFile is a FILE object and not a QFile, which isn't the case in your example.
A couple additional notes for beginners.
Related Note 1
You didn't ask about this, but I also added the QIODevice::Text flag to ensure that newline characters get translated to/from the local encoding (plain \n vs. \r\n) when you use endl.
A really common mistake is to use \r\n AND QIODevice::Text, which results in text files with double-returns \r\r\n on Windows. Just use QIODevice::Text when opening and simply \n or endl and you'll never have this problem.
Related Note 2
Using QTextStream::endl will automatically call flush() each time. If your loop is large, use "\n" instead to prevent a slowdown unless you actually need to flush every line. The stream will automatically write to disk as its buffer gets full, or when it's closed.
QFile::close() also calls flush(), which makes your mFile.flush() at the end redundant.

Use an overloaded constructor of QTextStream:
QTextStream in(&mFile, QIODevice::ReadWrite | QIODevice::Truncate);
The QIODevice::Truncate will remove all the previous content of the file, and QIODevice::ReadWrite will open it for read and write access.

Related

How to work around string splitting while loading a list from a file in QT

I'm trying to create a simple "To Do list" app in QT Creator while coding the part that loads and saves the list from a file I get stuck on a problem.
If you enter a string like "Do my homework" the program threads the string as it should, but when you load the program again the save file got split in words. So it gets all the entries but each word separated ("Do", "my", "homework").
What is the solution? I tried working with 'char arrays' and 'getline' but they give me nothing but errors.
Here is my code for the save and load parts:
void MainWindow::LoadList(){
std::ifstream load_file("./data.bin");
char loader[255];
while (load_file >> loader){
QString Writer = QString::fromStdString(loader);
ui->lstTaskList->addItem(Writer);
}
}
void MainWindow::SaveList(){
std::ofstream save_file("./data.bin");
for (auto i = 0; i < ui->lstTaskList->count(); i++){
QString Saver = ui->lstTaskList->item(i)->text();
std::string saver = Saver.toStdString();
save_file << saver << std::endl;
}
}
Can anyone help me with this, please?
My thanks in advance...
The anwser was using QFile and QByteArray for me, I knew about QFile but it tries using basic "std" c++ till I learned more about QT.

QTextStream atEnd() is returning true when starting to read from a file

I want to read and parse contents of the /proc/PID/status file on a linux machine, but the QTextStream.atEnd is always returning true when starting to read. The code:
QString procDirectory = "/proc/";
procDirectory.append(QString::number(PID));
procDirectory.append("/status");
QFile inputFile(procDirectory);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
QString line;
while (!in.atEnd())
{
line = in.readLine();
File exists and if I read lines manually without the while expression, the files are read normally.
Did I miss something obvious?
(Debian 8 x64, QT 5.4.1 x64, gcc 4.9.2)
Nevermind found out I needed to read one line before the while clause, now it works.
The preferred way oft looping over these streams is with a do/while loop. This is for allowing the stream to detect Unicode correctly before any queries (like atEnd) are made.
QTextStream stream(stdin);
QString line;
do {
line = stream.readLine();
} while (!line.isNull());

Finding a specific character in a file in Qt

How can i find a specific character in a QFile which has a text in it?
for example i have ' $5000 ' written somewhere in my file. in want to find the "$" sign so i will realize that I've reached the number.
I tried using QString QTextStream::read(qint64 maxlen) by putting 1 as the maxlen :
QFile myfile("myfile.txt");
myfile.open(QIODevice::ReadWrite | QIODevice::Text);
QTextStream myfile_stream(&myfile);
while(! myfile_stream.atEnd())
{
if( myfile_stream.read(1) == '$')
{
qDebug()<<"found";
break;
}
}
and i get "error: invalid conversion from 'char' to 'const char* "
i also tried using the operator[] but apparently it can't be used for files.
Read in a line at a time and search the text that you've read in
QTextStream stream(&myFile);
QString line;
do
{
line = stream.readLine();
if(line.contains("$"))
{
qDebug()<<"found";
break;
}
} while (!line.isNull());
The error message you've posted doesn't match the issue in your code. Possibly the error was caused by something else.
QTextStream::read returns QString. You can't compare QString and const char* directly, but operator[] can help:
QString s = stream.read(1);
if (s.count() == 1) {
if (s[0] == '$') {
//...
}
}
However reading a file by too small pieces will be very slow. If your file is small enough, you can read it all at once:
QString s = stream.readAll();
int index = s.indexOf('$');
If your file is large, it's better to read file by small chunks (1024 bytes for example) and calculate the index of found character using indexOf result and count of already read chunks.
a single char could be read with
QTextStream myfile_stream(&myfile);
QChar c;
while (!myfile_stream.atEnd())
myfile_stream >> c;
if (c == '$') {
...
}
myfile_stream.read(1) - this is not good practice, you should not read from file one byte at a time. Either read the entire file, or buffered/line by line if there is a risk for the file to be too big to fit in memory.
The error you get is because you compare a QString for equality with a character literal - needless to say that is not going to work as expected. A string is a string even if there is only one character in it. As advised - use either the [] operator or better off for reading - QString::at() const which is guaranteed to create no extra copy. You don't use it on the QFile, nor on the QTextStream, but on the QString that is returned from the read() method of the text stream targeted at the file.
Once you have the text in memory, you can either use the regular QString methods like indexOf() to search for the index of a contained character.
in want to find the "$" sign so i will realize that I've reached the
number.
It sounds to me that you're searching for the '$' symbol because you're more interested in the dollar value that follows it. In this case, I suggest reading the files line by line and running them through a QRegExp to extract any values you're looking for.
QRegExp dollarFind("\\$(\\d+)");
while(!myfile_stream.atEnd()){
QString line = myfile_stream.readLine();
if (dollarFind.exactMatch(line)){
QStringList dollars = dollarFind.capturedTexts();
qDebug() << "Dollar values found: " << dollars.join(", ");
}
}

Need to display in qtextEdit real time

I have an arm board with a touchscreen display, where I want to display the output from a certain function, vcm_test(). The output of this function is saved to a file called
test.txt . Now I am able to read the contents of the file test.txt and display it in my qtextEdit only if it is less than 50-60 lines. Whereas I have more than 7000 lines in the test.txt . When I try to display 7000 lines the arm board keeps reading and nothing is displayed until reading is complete. Is there any way to read and display after every line or say every 10 lines. I thought of using qProcess in readfile too, but I have no idea how I can do that.
connect(ui->readfil, SIGNAL(clicked()), SLOT(readfile()));
connect(ui->VCMon, SIGNAL(clicked()), SLOT(vcm_test()));
connect(ui->Offloaderon, SIGNAL(clicked()), SLOT(offloader_test()));
connect(ui->quitVCM, SIGNAL(clicked()),vcmprocess, SLOT(kill()));
connect(ui->quitoffloader, SIGNAL(clicked()),offloaderprocess, SLOT(kill()));}
MainWindow::~MainWindow(){
delete ui;}
void MainWindow::readfile(){
QString filename="/ftest/test.txt";
QFile file(filename);
if(!file.exists()){
qDebug() << "NO file exists "<<filename;}
else{
qDebug() << filename<<" found...";}
QString line;
ui->textEdit->clear();
if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
QTextStream stream(&file);
while (!stream.atEnd()){
line = stream.readLine();
ui->textEdit->setText(ui->textEdit->toPlainText()+line+"\n");
qDebug() << "line: "<<line;}
}
file.close();}
void MainWindow::vcm_test(){
vcmprocess->start("/ftest/vcm_test_2");}
void MainWindow::offloader_test(){
offloaderprocess->start("/ftest/off_test_2");}
Any advice is really appreciated.Thanks.
You could use QApplication::processEvents() after reading every line and appending it to your text edit. But you should be really careful when using this, and I would not recommend doing so. You should also consider using QTextEdit::Append() instead of setText.
A better solution is to read the file in another thread and use signals and slots to send read data that you want to append to your QTextEdit.

How to get magic number of a binary file

There is a magic number associated with each binary file , does anyone know how to retrieve this information from the file?
file <file_name>
magic numbers are usually stored in (linux):
/usr/share/file/magic
also check this link, someone was trying to use libmagic to get the information in C program, might be useful if you're writing something yourself.
Use libmagic from the file package to try and sniff out the type of file if that's your goal.
There are no general "magic" numbers in binary files on unix, though different formats might define their own. The above library knows about many of those and also use various other heuristics to try and figure out the format/type of file.
The unix file command uses magic number. see the file man page for more.(and where to find the magic file )
Read this: http://linux.die.net/man/5/magic
It's complex, and depends on the specific file type you're looking for.
There is a file command which in turn uses a magic library, the magic library reads from a file found in /etc called magic (this is installation dependant and may vary), which details what are the first few bytes of the file and tells the file what kind of a file it is, be it, jpg, binary, text, shell script. There is an old version of libmagic found on sourceforge. Incidentally, there is a related answer to this here.
Hope this helps,
Best regards,
Tom.
Expounding on #nos's answer:
Example below uses the default magic database to query the file passed on the command line. (Essentially an implementation of the file command. See man libmagic for more details/functions.
#include <iostream>
#include <magic.h>
#include <cassert>
int main(int argc, char **argv) {
if (argc == 1) {
std::cerr << "Usage " << argv[0] << " [filename]" << std::endl;
return -1;
}
const char * fname = argv[1];
magic_t cookie = magic_open(0);
assert (cookie !=nullptr);
int rc = magic_load(cookie, nullptr);
assert(rc == 0);
auto f= magic_file(cookie, fname);
if (f ==nullptr) {
std::cerr << magic_error(cookie) << std::endl;
} else {
std::cout << fname << ' ' << f << std::endl;
}
}

Resources