How to modify a binary file - c++

I am trying to modify some values in a binary file. This is how I create it and I read it:
void Save()
{
User user1;
user1.Rol=1;
user1.Name="John";
user1.Pass="test1";
User user2;
user2.Rol=2;
user2.Name="Bob";
user2.Pass="test2";
QFile file("users.txt");
if(!file.open(QIODevice::WriteOnly))
{
qDebug()<< "Error.";
return;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_5_5);
out << user1;
out << user2;
file.flush();
file.close();
}
I want to know how I can modify a "John".
void Load()
{
User user;
QFile file("users.txt");
if(!file.open(QIODevice::ReadOnly))
{
qDebug()<< "Error.";
return;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_5_5);
while(!in.atEnd())
{
in >> user;
if(user.Name=="John")
{
qDebug() << user.Name << " is " << user.Rol << " and he has the password: " << user.Pass;
}
}
file.close();
}
The result is: "John" is 1 and he has the password: "test1". I want to modify this to: "John" and he has the password: "test3" but I don't know how I can modify it.
I've reading the documentation but I haven't found a good example.

Related

Why is the QByteArray read from a file smaller than the newly downloaded QByteArray?

I am attempting to compare a QByteArray of an already saved html file with a QByteArray that was just downloaded. I have to convert the QString of the file's contents to QByteArray in order to compare them (or vice versa) and comparing bytes seems like the cleanest method, however when converted from QString to QByteArray, the size of the new QByteArray is smaller than what it should be. QByteArray QString::toLocal8Bit() const states that if it is undefined, the characters will be suppressed or replaced. It also said that it uses toLatin1() by default and tried to use ASCII since that is what a website is encoded in. I still get the same results.
bool NewsBulletin::compareDownload(QByteArray new_contents, QString filename)
{
bool return_what = false;
qDebug() << "I am in compareDownload";
// qDebug() << new_contents[1];
// qDebug() << new_contents[1] << endl
// << new_contents[2];
QFile file(application_path + filename);
if (file.exists())
{
// QString new_contents_qstr(new_contents);
file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
QTextCodec::setCodecForLocale(QTextCodec::codecForName("ASCII"));
QString file_contents = in.readAll();
QByteArray file_byte_array = file_contents.toLocal8Bit();
qDebug() << "outputting new file array";
qDebug() << new_contents[5] << new_contents.size();
qDebug() << "outputting old file array";
qDebug() << file_byte_array[5] << file_byte_array.size();
for (int i=0; i<=file_byte_array.size(); i++)
{
if (file_byte_array[i] != new_contents[i])
{
return_what = true;
break;
}
else if (i == file_byte_array.size())
{
qDebug() << "compareDownload will return false, duplicate file.";
return_what = false;
}
}
}
else
{
qDebug() << "compareDownload will return true, DNE.";
return_what = true;
}
return return_what;
}
The output of the qDebug() from the function is:
I am in compareDownload
outputting new file array
T 64704
outputting old file array
T 64576
After reading the api for hours, I found the reason for the bytes being different.
file.open(QIODevice::ReadOnly | QIODevice::Text);
QIODevice::Text needs to be removed. This flag changes end of line terminators into the terminator for cpp, "\n", thus giving a byte difference.

Rename file if button is pressed in TreeView Qt

I have a treeview that displays a folder with text files. There is a 'open' button. That will open the file. But when this button is pressed it should rename the file to: read filename.txt. So if there is a file for example that is name nameslist.txt and the button is pressed it should rename it to read nameslist.txt or something similar. I thought of something like this:
void berichtenhistorie::on_Openbutton_released()
{
QModelIndex index = ui->treeView->currentIndex();
QString name = index.fileName();
QString path = index.filePath();
QFile file(path);
file.open(QIODevice::WriteOnly | QIODevice::Text);
file.rename("read " + name);
file.close();
}
But this isnt working. I get the following error's:
error: C2352: 'QDirModel::fileName' : illegal call of non-static member function
But I dont know how to use fileName() and filePath() correctly.
Thanks for help!
I think that here is what you looking for:
void berichtenhistorie::on_Openbutton_released()
{
QModelIndex index = ui->treeView->currentIndex();
QFileSystemModel *model = (QFileSystemModel*)ui->treeView->model();
QString path = model->filePath(index);
QString name = model->fileName(index);
QString dir = path;
dir.remove(dir.size() - name.size(), name.size());
QFile file(path);
if(file.open(QIODevice::WriteOnly | QIODevice::Text))
{
//Interact with the file
file.close();
if(file.rename(QString("%1read %2").arg(dir, name)))
qDebug() << "Renamed";
}
}
Here's a break out of each step you'll need to do to work with QFile.
QFile file("test.txt");
if(file.exists())
{
qDebug() << "found file";
if(file.open(QIODevice::ReadWrite))
{
qDebug() << "opened";
if(file.rename("text1.txt"))
{
qDebug() << "renamed";
}
else
{
qDebug() << "failed to rename";
}
file.close();
}
}
else
{
qDebug() << "file does not exist";
}
In the end, you'll only really need your debugger to step through instead of printing out everything known to your application. E.g.
QFile file("test.txt");
if(file.exists() && file.open(QIODevice::ReadWrite))
{
if(file.rename("text1.txt"))
{
qDebug() << "renamed";
}
file.close();
}

Qt c++ save object to a file

I'm trying to save an object called f to a file, getting errors: no match for operator << in stream << f
here is the function:
void FilmWriter::saveFilm(Film& f){
QString fileName = QFileDialog::getSaveFileName(this,("Save File"));
if (fileName != "") {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::critical(this, ("Error"),("Could not open file"));// error message
} else {
QTextStream stream(&file);
stream << f;
stream.flush();
file.close();
}
}
}
Please let me know if you need any more information?
These are 2 functions in a different class filmInput
void FilmInput::getFilm(){
Film f1(titleEdit->toPlainText(),durationEdit->toPlainText().toInt() ,directorEdit->toPlainText(),
QDate::fromString(relDateEdit->toPlainText(),"dd/MM/YYYY"));;
obtainFilmData(f1);
}
void FilmInput::obtainFilmData(Film &f){
saveFilm(f);
}
QTextStream is made for storing text, not Film. You need something that can store your object. Maybe QDataStream will help you? But you'll need to serialize your Film object to something like QByteArray.Update:
Now I see that you need Film::toString() method that will give you a string representation of Film object. Then you just write stream<<f.toString(); instead of stream<<f;. Or you can implement operator<< that takes QTextStream and Film.
Example of Film::toString():
QString Film::toString()
{
return mTitle + " " + mDuration + " " + mDirector + " " + mDate.toString();
}
with the function below (which may not be 100% syntacticly correct) you can now write to your stream, Film.toString()
QString Film::toString()
{
QTextStream stream;
stream << someFilmVariable << " " << someOtherFilmVariable;
return stream.string()
}

Qt reading from QTextStream

I'm trying to read a text file and display the contents in a QPlainTextEdit. Please can you point out what I'm doing wrong:
QFile jsonFile("data.json");
if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Failed to open file";
qDebug() << jsonFile.errorString();
return;
}
else
{
qDebug() << "File opened";
} //It returns that the file opened successfully
qDebug() << "File Exists?: " << jsonFile.exists(); //Yep, it exists.
QTextStream outStream(&jsonFile);
QString textString = outStream.readAll();
qDebug() << "Text string: " << textString; //textString is empty! ""
ui->fileToPost->setPlainText(textString); //fileToPost is the QPlainTextEdit
jsonFile.close();
If I do something like
QString textString = "The cat sat on the mat";
it displays fine. The problem is that nothing is being read from the stream (or maybe the file).
Try to check file's absolute path, probably it is not where, you expect it: qDebug()<<QFileInfo("data.json").absoluteFilePath();

Qt Qvariantlist conversion into javascript array unsuccessful

I'm currently create an apps in Meego using QML and JS on most of the part. and now I stumbled upon a problem.
From javascript I want to call a C++ function to read text file, parse it, and then return an array of the parsing result.
so I create a Q_INVOKABLE function called parse() and call it through javascript
function parse() {
var myArray = new Array();
myArray = parser.parse("/home/user/MyDocs/angklungtext.txt")
if(myArray === undefined){
console.log("null found");
}
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i][0] + "," + myArray[i][1])
}
}
and here is the parse function in C++
QVariantList* QMLParser::parse(QString filename)
{
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug()<< dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists())
{
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
QVariantList* myList = new QList<QVariant>;
while(!stream.atEnd())
{
QString line = stream.readLine();
qDebug() << line.trimmed();
QStringList lineList = line.split(":");
myList->append(lineList);
}
file.close();
return myList;
}
sadly.
when I try to run it it giving a result like this
start debugging
"/home/user/MyDocs/angklungtext.txt"
"/home/developer"
"/home/user/MyDocs/angklungtext.txt"
"1:1000"
"4:2000"
"5:3000"
"2:4000"
null found
file:///opt/memoryreader/qml/memoryreader/myjs.js:8: TypeError: Result of expression 'myArray' [undefined] is not an object.
looks like the C++ parse function successfully parsing the file. it can read it and it can save it into the QVariantList.
but after it return the result into javascript myArray still [undefined].
is there something wrong with the conversion?
Just simplify the C++ side like this :
QVariant QMLParser::parse(QString filename)
{
QStringList myList;
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug() << dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists()) {
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
while(!stream.atEnd()) {
QString line = stream.readLine();
qDebug() << line.trimmed();
myList << line.trimmed().split(":");
}
file.close();
return QVariant::fromValue(myList);
}
And it should work !
Just remember, QML must see a QVariant, even if a QList is wrapped inside it, and Qt is able to convert most of its base types to QVariant using QVariant::fromValue(T) so use it extensively.
Oh and BTW a QVariant is reference not pointer.
Haven't done this myself, so I'm just thinking out loud. But I note that you're returning a pointer to a QVariantList...which looks suspect. (Also: if you new, then who would do the delete?)
Have you tried returning it by value?