QTextStream write data in file - c++

I'm learning QtCreator and having troubles writing data in file. Here's some code :
char *str;
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2) {
str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
std::cout << str << std::endl;
out << str << "\n";
i += 2;
}
getItem returns a QWidget * from a QFormLayout filled with QLineEdit (that explains the dynamic cast). Anyway, when I pass str into std::cout it works fine, the data is printed, but when I pass str into out, it writes only the first char of str in the file.
I don't get what I'm doing wrong, I really would appreciate any tips.

This line is a problem: str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
dynamic_cast<QLineEdit *>(this->getItem(i))-> is OK
->text() creates a temporary QString
.toLocal8Bit() creates a temporary QByteArray
.data() returns a pointer to the internal data of the QByteArray
As soon as the line is passed the QByteArray will be destroyed and you have a dangling pointer. str points to invalid data.
Everything you do with this pointer afterwards (except letting it point to somewhere else) is undefined behaviour.
Try to use something like this:
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2)
{
QLineEdit* lineEdit = dynamic_cast<QLineEdit *>(this->getItem(i));
if (lineEdit)
{
QByteArray str = lineEdit->text().toLocal8Bit();
std::cout << str.data() << std::endl;
out << str.data() << "\n";
i += 2;
}
else
{
std::cerr << "Item at " << i << " is no QLineEdit*" << std::endl;
}
}
out.close();
Also please check whether QFile is actually open and whether QTextStream reports some errors when writing.

Related

Is there a way to put "QByteArray" variable data directly into "int" variable without casting?

The conversion you're trying to do is not just converting the QByteArray data to an int.
For example, assuming that QByteArray a [3] contains [0] = 36, 1 = 23, and [2] = 12 data, use the b variable in the form of int b in the form b = 362312. I want to do it.
In order to use QByteArray data as int data, QByteArray variable is assigned to QString variable and cast to string variable.
And I tried to print out the string variable, but the strange unknown data is output.
I tried to cast a string using toInt () after confirming that the string is printed normally, but the string is printed as strange characters.
So I could not do toInt ().
I run a lot of tests and the code is messy.
The reason I didn't delete the comment was not to show that I've tried various things.
if (QCanBus::instance()->plugins().contains(QStringLiteral("socketcan"))) {
qWarning() << "plugin available";
}
QString errorString;
QCanBusDevice *device = QCanBus::instance()->createDevice(
QStringLiteral("socketcan"), QStringLiteral("vcan0"), &errorString);
if (!device) {
qWarning() << errorString;
} else {
device->connectDevice();
std::cout << "connected vcan0" << std::endl;
device->connect(device, &QCanBusDevice::framesReceived, [this, device]() {
QCanBusFrame frame = device->readFrame();
QString testV = frame.toString();
// int testI = testV.split(" ")[0].toInt();
QString qvSpeed = frame.payload();
// int a = frame.payload().length();
std::string text = testV.toUtf8().constData();
std::string vSpeed = qvSpeed.toLocal8Bit().constData();
//At that point the vVal values ​​are being updated in real time.
//I want to pass the updated vVal to qml gui in real time.
// int vVal = static_cast<int>(frame.payload()[0]);
// for(int i = 0; i < frame.payload().length(); ++i)
// std::cout << std::hex << static_cast<int>(frame.payload()[i]);
// std::cout << std::endl;
// if(vVal)
// int tSpeed = static_cast<int>(frame.payload()[0]);
// std::stringstream stream;
// stream <<
testVal1 += 0;
// if(frame.frameId() == 001)
// testVal2 = static_cast<int>(frame.payload()[0]);
// testVal2 += 20;
// duration += 200;
// emit sendMessage(testVal1, testVal2);
std::cout << vSpeed << std::endl;
// if(frame.frameId() == 001)
// std::cout << testI << std::endl;
// std::cout << "--------------" << std::hex << static_cast<int>(frame.payload()[0]) << "----------------" << std::endl;
});
}
Finally, QByteArray a [3] = {32, 34, 12};
Assuming you have data, you want to use this like int b = 323412.
In order to do that, I thought it would convert to a string and then to an integer, but even strings are not normal output.
I'm also attaching the strange string that is currently printed out below.
enter image description here
Since QByteArray stores its data as char * you can just cast its internal data, for example:
#include <QCoreApplication>
#include <iostream>
#include <iomanip>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
uint32_t num = 1234;
std::cout << "original number:" << num << std::endl;
std::cout << "bytes: " << std::endl;
QByteArray arr(reinterpret_cast<char *>(&num), sizeof(uint32_t));
for(int i = 0;i < arr.size();i ++)
{
std::cout << " 0x" << std::hex << std::setfill('0') << std::setw(2) << (arr.at(i) & 0xFF) << std::endl;
}
uint32_t *num2 = reinterpret_cast<uint32_t *>(arr.data());
std::cout << "casted number :" << std::dec << *num2 << std::endl;
return a.exec();
}
But I would not recommend this 'C' approach since it is fraught with errors.
Btw, I've never seen CAN data converted to QString. Usually it just 8 bytes of data, you worth cast it to a data struct instead, for example:
struct Data
{
uint32_t value1;
uint32_t value2;
} inData, outData;
inData.value1 = 1234;
inData.value2 = 5678;
QByteArray arr(reinterpret_cast<char *>(&inData), sizeof(Data));
outData = *reinterpret_cast<Data *>(arr.data());
//memcpy(&outData, arr.data(), static_cast<size_t>(arr.size())); // or this

Variable change without any direct action

I have wrote an API as defined below. This API is used to find the index of a filename in a file system. The filesystem is coming from an Android device through mtp. What I'm doing is to request a list of files stored on the Android device and compare each file listed to the one I'm looking for 'name2look'
I have created a vector table to store what I'm doing but it's not mandatory. My concerns is that the variable name2look contain the right name I'm looking for "Pictures"
uint32_t USBDevice::GetIndexFromName(LIBMTP_mtpdevice_t *dev, uint32_t storage,const char *name2look)
{
uint32_t idx_fold = 1;
std::vector<MyFileTreeItem*> FSimage;
LIBMTP_file_t *files;
LIBMTP_file_t *file;
std::cout << "NAME : " << name2look << "\n";
files = this->GetFileAndFolder(dev, storage,0);
file = files;
while (file != NULL) {
MyFileTreeItem* FSitem = new MyFileTreeItem();
FSitem->filename = file->filename;
FSitem->index = file->item_id;
FSitem->FileType = file->filetype;
FSimage.push_back(FSitem);
std::cout << "NAME : " << name2look << "\n";
std::cout << "FS NAME : " << file->filename << "\n";
if(std::strcmp(file->filename, name2look)==0) {
std::cout << "FIND IDX : " << file->item_id << "\n";
return file->item_id;
}
file = file->next;
}
return 0;
}
The Log is showing that the first display 'std::cout' is ok. the variable name is still 'Pictures' but when I ask to display it after in the "while" the variable name2look change and is not the same anymore.
First display
NAME : Pictures
second one in the while
NAME : Martin).mp3
FS NAME : Music
How is it possible to be corrupted ??
The function is called by a Qt C++ code:
void MyButtonGroup::buttonClick(QAbstractButton *button)
{
uint32_t status;
QList<QTreeWidgetItem *> itemList;
uint32_t index = 0;
if (button->text() == "Create Folder") {
itemList = this->MyTree->selectedItems();
QString str = itemList[0]->text(0);
char *utf8_text = str.toLatin1().data();
if(utf8_text != NULL)
{
std::cout << "A CHERCHER " << utf8_text << "\n";
index = this->MyDevice.GetIndexFromName(this->dev_id, storage->id, utf8_text);
}
else
index = 0;
CreateFolderDialog *dialog = new CreateFolderDialog(this->MyTree, this->MyDevice, this->dev_id, this->storage, index);
dialog->show();
}
utf8_text report the right value.
Any idea ?
This might be the problem. I am not sure. Check it out.
This line:
char *utf8_text = str.toLatin1().data();
What does the documentation say toLatin1() does? It creates a new QByteArray object and then you call data() on that and you get a pointer to character and then the QByteArray is destroyed at the end of the line because it was TEMPORARY.
And now you have an invalid pointer to freed memory that you then pass into your function. It probably gets overwritten by the first call to new() in your function.
I think you should change it to something like this:
QByteArray latin_str = str.toLatin1();
char *utf8_text = latin_str.data();
Your name utf8_text is weird since you just converted it to Latin1 which isn't UTF8.

Stock bytes in QVariantMap

I'm getting the bytes data from a QImage in a QByteArray and i want to write the datas from the QByteArray in a QVariantMap, but after stocking the bytes, the bytes are changed and the image is not valid...
I tried to stock the QByteArray directly but the thing is i'm going to receive QVariantMap (as a JSON) from Windows phone, android and iOS. And the QByteArray will not exist on those OS so i doubt that the .toByteArray function will work...
Here is an example of what i tried using a QString but the bytes are changed when the QString is filled...
QFile tmp("default_profile.jpg");
tmp.open(QIODevice::ReadOnly);
if (tmp.exists() == true)
{
QByteArray tab;
tab = tmp.read(tmp.size());
int i = 0;
char *data = tab.data();
QString str;
while (i != tmp.size())
{
if (i < 100)
qDebug() << "AVANT = " << " i = " << i << "[" << *data + '0' << "]";
i++;
str.append(*data);
++data;
}
QVariantMap *tmp = new QVariantMap();
(*tmp)["name"] = "test.jpg";
(*tmp)["data"] = str;
(*tmp)["size"] = tab.size();
(*tmp)["type"] = "PhonePic";
this->fileReceived("", "", tmp);
}
And here is the fileReceived:
QFile tmp((*src)["name"].toString());
tmp.open(QIODevice::ReadWrite | QIODevice::Truncate);
char *test = (char *)malloc((*src)["size"].toInt());
QString str;
str = (*src)["data"].toString();
int i = 0;
char *data = const_cast<char *>(str.toStdString().c_str());
while (i != 8143)
{
if (i < 100)
qDebug() << "AFTER = " << " i = " << i << "[" << *data + '0' << "]";
i++;
++data;
}
qDebug() << tmp.write(str.toStdString().c_str(), (*src)["size"].toInt());
The size of the "AFTER" QString is good, but the values are not good...
Does someone know what i'm doing wrong ? or maybe have an idea of how i get do it ?
Thanks for people who will try to help me.
You load binary data into a QByteArray. Then you append the data in this QByteArray byte by byte to a QString, which converts every single byte into unicode. And last but not least you you just try to cast this back into raw data? No way. So pointing you to what you are doing wrong was easy.
Helping you is much more difficult. Why do you think you can use QString, when QByteArray is not available? When QVariantMap is available, then you have a complete Qt. So using QByteArray should not be a problem. But I must admit, I don't fully understand your post and your problem, so I might overlook something.
You can send a QImage directly in a QVariant or QVariantMap. How the particular json library that you use will deal with the json-to-Qt interface, that's a whole another story.
Since QVariant is in Qt Core and not Qt Gui, you have to use QVariant::value() or the qvariant_cast() template function when working with GUI types such as QImage.

Segmentation fault with a element of QList

In my application I have a list of pointer to QFile objects:
QList<QFile*> files
This function adds the elements on the list:
void MumuServer::openFiles(){
QDir fileDir(QDir::toNativeSeparators(homeApp.path() + "/file"));
std::cout << fileDir.path().toStdString() << std::endl;
if(fileDir.exists()){ // there is files directory in the application home dir
std::cout << "fileDir exists" << std::endl;
QStringList filesList = fileDir.entryList();
for(int index = 0; index < filesList.size(); index++){
QString fileName = filesList.at(index);
if(this->blackListFile.contains(fileName)){
continue;
}
QString path = fileDir.path() + "/" + fileName;
std::cout << path.toStdString() << std::endl;
QFile file(QDir::toNativeSeparators(path));
if(file.exists()){
files.append(&file);
}
}
std::cout << this->files.size() << " files found" << std::endl;
}
After this function the QFile pointers are added on the QList. But, when I try to manipulate something on a element of the list getting it with the function at(int) a segmentation fault occurs.
Example:
QFile * file = files.at(index);
std::cout << "File size = " << file->fileName() << std::endl;
Somebody are seeing what am I doing wrong?
The objects that you put into your 'files' list have gone out of scope and were destroyed. Use the 'new' operator to allocate them instead. Be sure to delete them when you are done or you will have a memory leak.
QFile* file = new QFile(QDir::toNativeSeparators(path));
if(file->exists()){
files.append(file);
}

How can I extract the displayed text from a QTableWidgetItem?

I have a subclass of QTableWidget with the following code:
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(pushCellChange(int, int)), Qt::QueuedConnection);
...
void MyTableView::pushCellChange(int row, int column)
{
QString text(item(row, column)->text());
QByteArray data = text.toAscii();
cout << data.length() << endl;
const char* cellData = text.toAscii().constData();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
}
When I change the upper-right cell to anything this outputs:
2
Cell (0, 0) changed to: ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌░▬∟C▌▌
However, while this corrupt data is spewed out on the console, the table widget itself seems to behave normally and shows the correct string. Does anyone know what is going on here?
The call toAscii() is storing the QString's data to a QByteArray. In your code, you do this twice:
QByteArray data = text.toAscii();
const char* cellData = text.toAscii().constData();
_____________^ <-- temporary QByteArray
The const char* is actually pointing to the data within a temporary variable, which goes out of scope at the semicolon, at which point the pointer becomes invalid. If instead you were to make use of the local variable data, you'd be OK:
const char* cellData = data.constData();
___^ <-- still-in-scope QByteArray
Alternatively, you can do this all in-line with the cout and the data will still be valid when it is copied to the output stream:
cout << "Cell ("<<row<<","<<column<<") changed to: " << text.toAscii().constData() << endl;
std::string cellData = text.ToStdString();
cout << "Cell ("<<row<<", "<<column<<") changed to: " << cellData << endl;
That should work fine. As for why toAscii doesn't work, I have no clue.
If it's just about the console output, you could also use qDebug() (available after #include <QDebug>) and pass the QString directly:
void MyTableView::pushCellChange(int row, int column)
{
qDebug() << item(row, column)->text().length();
qDebug() << "Cell (" << row << ", " << column << ") changed to: "
<< item(row, column)->text();
}
This way, you don't have to mess with data conversion …