I have no idea why, but i can´t get the simplest example of QTemporaryFile to run... My real intent is to write data from QAudioInput into a temporary file before it is processed later.
After trying several times I realized that neither .read(), .readLine(), .readAll() or .write() would have any effect... The error string is always "Unknown Error" and it neither works for QFile or QTemporaryFile.
#include <QCoreApplication>
#include <QTemporaryFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QTemporaryFile tf;
tf.open();
tf.write("Test");
QTextStream in(&tf);
qDebug() << "Testprogramm";
qDebug() << tf.isOpen();
qDebug() << tf.errorString();
qDebug() << in.readLine();
qDebug() << tf.readAll();
tf.close();
return a.exec();
}
The debug posts:
Testprogramm
true
"Unknown error"
""
""
Thank you in advance!
You need to move the file pointer back to the beginning of the file. This has to be done on the file itself when there's no stream on the file, or using the stream when one exists. Also - QFile is a proper C++ class that manages the file resource. There's no need to manually close the file. QFile::~QFile does that job.
The following works just fine:
#include <QtCore>
int main() {
auto line = QLatin1String("Test");
QTemporaryFile tf;
tf.open();
Q_ASSERT(tf.isOpen());
tf.write(line.data());
tf.reset(); // or tf.seek(0)
QTextStream in(&tf);
Q_ASSERT(in.readLine() == line);
in.seek(0); // not in.reset() nor tf.reset()!
Q_ASSERT(in.readLine() == line);
}
The above also demonstrates the following techniques applicable to sscce-style code:
Inclusion of entire Qt module(s). Remember that modules include their dependencies, i.e. #include <QtWidgets> is sufficient by itself.
Absence of main() arguments where unnecessary.
Absence of QCoreApplication instance where unnecessary. You will get clear runtime errors if you need the application instance but don't have one.
Use of asserts to indicate conditions that are expected to be true - that way you don't need to look at the output to verify that it is correct.
Use of QLatin1String over QStringLiteral where ASCII strings need to be compared to both C strings and QStrings. Implicit ASCII casts can be a source of bugs and are discouraged.
QLatin1String is a constant (read-only) wrapper, designed to wrap C string literals - thus there's no need to make line additionally const, although in real projects you'd want to follow the project's style guide here.
Related
Here is the qt code that crash:
Writing the content of a 130MB binary file will crash, but writing a 2MB binary file will not.
Is there any solution for writeTextElement to write big file content? Thanks
env: qt opensource 4.8.7
Visual Studio 2010
Windows 10
big file: https://1drv.ms/u/s!Ap_EAuwC9QkXijOmXqxp9DEav3gm?e=iha0uI
test project: https://1drv.ms/u/s!Ap_EAuwC9QkXijWzOlpaWmtzOdtz?e=fDpo93
#include <QtCore/QCoreApplication>
#include <QFile>
#include <QXmlStreamWriter>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray mContentBuffer;
QFile file("C:\\Work\\bigfile.xar");
if(!file.open(QFile::ReadOnly))
{
return -1;
}
mContentBuffer = file.readAll();
file.close();
QFile profile("C:\\Work\\profile.xml");
if(!profile.open(QFile::WriteOnly|QFile::Truncate))
{
return -1;
}
QXmlStreamWriter stream(&profile);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
stream.writeTextElement("Content", mContentBuffer.toBase64());
stream.writeEndElement(); // Profile
stream.writeEndDocument();
return a.exec();
}
The minimal reproducible example was a life saver.
Several things seem to be required to solve your issue in a clean way.
Mainly, the file must be read in chunks.To be precise and as mentioned in that other question, in chunks whose size is a multiple of 3 bytes (I have hardcoded 9000 below).You will need to look for the value that gives you the best performance while guaranteeing it never fails yourself.
Instead of writing in the XML in 1 go, I made it so the XML file is being written each chunk at a time.To achieve that, the code creates the node first, then uses the writeCharacters method to write text in it.
Note the if (mContentBuffer.isEmpty()) right before writing. It is indeed specified in Qt Assistant that the read function has no way of reporting errors; returning an empty QByteArray can mean either that no data was currently available for reading, or that an error occurred. Considering the while loop, it can only be an error, so we abort everything.BTW, I think but have not tested that you can just end the document, and the XML stream writer will close everything it needs to have a valid XML.
Just to make it clean, I reordered the lines of codes so that the XML file is opened before the xar file. I also added QtCore/ on every include. Not sure that last point is going to be useful on your real code.
This code implements all the above changes.It should not crash and while you will not be able to test the output on the 130MB file, you should be able to test your code vs mine on the 2MB file you has successfully read from before.
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QXmlStreamWriter>
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QFile profile("C:\\Work\\profile.xml");
if (!profile.open(QFile::WriteOnly | QFile::Truncate))
return -1;
QXmlStreamWriter stream(&profile);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("Profile");
stream.writeStartElement("Content");
QFile file("C:\\Work\\bigfile.xar");
if (!file.open(QFile::ReadOnly))
return -1;
while (!file.atEnd()) {
QByteArray mContentBuffer = file.read(9000);
if (mContentBuffer.isEmpty()) {
stream.writeEndDocument();
file.close();
profile.close();
return -1;
}
stream.writeCharacters(mContentBuffer.toBase64());
}
file.close();
stream.writeEndElement(); // </Content>
stream.writeEndElement(); // </Profile>
stream.writeEndDocument();
return a.exec();
}
Using console, I want to write the desired user's input into a file via getline function inside the wFile function and then read it. I face with logical error during Runtime; whatever I as user write doesn't type into the output terminal and it doesn't succeed more steps. Apparently fwrite function with this feature in the libraries exists, but I want to write my own code differently this way. I think I must have neglected a point. Here's the code:
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <String>
#include <cstdlib>
using namespace std;
void wFile(QString Filename)
{
QFile mFile(Filename);
QTextStream str(&mFile);
qDebug() << "what do you want to write in the desired file: ";
istream& getline (istream& is, string& str);
if (!mFile.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "could not open the file";
return;
}
mFile.flush();
mFile.close();
}
void read (QString Filename){
QFile nFile(Filename);
if(!nFile.open(QFile::ReadOnly | QFile::Text))
{
qDebug() << "could not open file for reading";
return;
}
QTextStream in(&nFile);
QString nText = in.readAll();
qDebug() << nText;
nFile.close();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString nFilename ="P:/DocumentArminV.txt";
wFile(nFilename);
read(nFilename);
return a.exec();
}
Spoiler alarm: At the very end of this answer, there is a very simple recommendation for a fix.
What OP did
Concerning istream& getline (istream& is, string& str); in wFile(QString Filename):
This declares function getline() in function wFile().
This is a valid declaration concerning C++.
Concerning the sample code, I missed the respective headers. IMHO,
#include <istream> and
#include <string>
are required to make this compiling.
However, it is possible that the existing #includes include them indirectly. So, OP's code may even compile without them.
Declaring functions, which are not used as well as re-declaring functions which are already declared is somehow useless but not wrong.
To demonstrate this, I made a small sample:
#include <cstdio>
#include <istream>
#include <string>
void func()
{
puts("in func()\n");
std::istream& getline(std::istream&, std::string&);
// Even duplicated prototyping is accepted without complaints:
std::istream& getline(std::istream&, std::string&);
}
int main ()
{
func();
return 0;
}
compiles and runs perfectly.
Output:
in func()
Live Demo on coliru
What OP (probably) wanted
Using console, I want to write the desired user's input into a file via getline function inside the wFile function and then read it.
This sounds a bit confusing to me. std::getline(std::cin, ) can be used to read user input from console. May be, it's a bit bad wording only.
Assuming, the OP wanted to read input from console, obviously, declaring a function is not sufficient – it must be called to become effective:
#include <iostream>
void func()
{
std::cout << "Enter file name: ";
std::string fileName; std::getline(std::cin, fileName);
std::cout << "Got file name '" << fileName << "'\n");
}
int main ()
{
func();
return 0;
}
Output:
Enter file name: test.txt↵
Got file name 'test.txt'
Live Demo on coliru
C++ std vs. Qt
Qt is undoubtly built on top of the C++ std library. However, though it's possible it is not recommended to mix both APIs when it can be prevented (or there aren't specific reasons to do so).
Both, Qt and C++ std, are a possibility to write portable software.
Qt covers a lot of things which are provided in the std library as well but a lot of other things additionally which are not or not yet part of std. In some cases, the Qt is a bit less generic but more convenient though this is my personal opinion. IMHO, the following explains how I came to this:
std::string vs. QString
std::string stores a sequence of chars. The meaning of chars when exposed as glyph (e.g. printing on console or displaying in a window) depends on the encoding which is used in this exposing. There are lot of encodings which interprete the numbers in the chars in distinct ways.
Example:
std::string text = "\xc3\xbc";
Decoded/displayed with
Windows-1252: ü
UTF-8: ü
Based on character type of std::string, it is not possible to determine the encoding. Hence, an additional hint must be provided to decode this properly.
(AFAIK, it is similar for std::wstring and wchar_t.)
QString stores a sequence of Unicode characters. So, one universal encoding was chosen by design to mitigate the "encoding hell".
As long as the program operates on QString, no encoding issues should be expected. The same is true when combining QString with other functions of Qt. However, it becomes a bit more complicated when "leaving the Qt universe" – e.g. storing contents of a std::string to QString.
This is the point where the programmer has to provide the additional hint for the encoding of the contents in std::string. QString provides a lot of from...() and to...() methods which can be used to re-encode contents but the application programmer is still responsible to chose the right one.
Assuming that the intended contents of text should have been the ü (i.e. UTF-8 encoding), this can be converted to QString (and back) by:
// std::string (UTF-8) -> QString
std::string text = "\xc3\xbc";
QString qText = QString::fromUtf8(text.c_str());
// QString -> std::string (UTF-8)
std::string text2 = qText.toUtf8();
This has to be considered when input from std::cin shall be passed to QString:
std::cout << "Enter file name: ";
std::string input; std::getline(std::cin, input);
QString qFileName = QString::fromLocal8Bit(input);
And even now, the code contains a little flaw – the locale of std::cin might have changed with std::ios::imbue(). I must admit that I cannot say much more about this. (In daily work, I try to prevent this topic at all e.g. by not relying on Console input which I consider especially critical on Windows – the OS on which we usually deploy to customers.)
Instead, a last note about OP's code:
How to fix it
Remembering my above recommendation (not to mix std and Qt if not necessary), this can be done in Qt exclusively:
QTextStream qtin(stdin);
qtin.readline();
I must admit that I never did it by myself but found this in the Qt forum: Re: stdin reading.
I'm making a simple Qt app that reads stuff from a CSV file and generates a PCAP data file out of it for reading by some other software.
And so soon as I invoque pcap_open_dead, pcap_dump_open or pcap_dump, I get no more console output upon running my small converter. Even the Hello World that comes at the beginning of the main doesn't show up any more. From the code below, if I simply comment out those three methods, the console output and "Hello World" come back.
Being new and therefore clueless about pcap, I ask for help.
#include <QCoreApplication>
#include <iostream>
#include "pcap.h"
using namespace std;
struct pcapWriter_S
{
bool isAvailable;
int m_OutPcapIpId;
pcap_t* m_OutPcapHandle;
pcap_dumper_t* m_OutPcapFile;
}m_pcapWriter;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout << "Hello World!" << endl;
//m_pcapWriter.m_OutPcapHandle = pcap_open_dead(DLT_EN10MB,65535);
//m_pcapWriter.m_OutPcapFile = pcap_dump_open(m_pcapWriter.m_OutPcapHandle, QString("tmp_csv_out.pcap").toAscii().data());
m_pcapWriter.m_OutPcapIpId = 1;
if (m_pcapWriter.m_OutPcapFile != 0)
{
m_pcapWriter.isAvailable = true;
}
QByteArray pkt_data;
// Omitted code to generate pkt data from input file
m_pcapWriter.m_OutPcapIpId++;
//pcap_dump((unsigned char*)m_pcapWriter.m_OutPcapFile, &header, (unsigned char*)pkt_data.data());
return a.exec();
}
Somehow this was due to me calling pcap_open but not pcap_close quite yet. In between console stuff gets lost - can't swear it gets written on the pcap thing but it blocks the console anyway.
I was trying to use a for each [Modern c++ style] but the code is crashed each time!
It was something like :
for(auto &k:mimeData->formats())
{ ... }
And later out of my surprises I found that the QStringList returned by formats is either invalid or completely separate object though the internal data is ought to be same!
So I tried to figure out in more simple example :
#include <iostream>
#include <string>
#include <list>
#include <QCoreApplication>
#include <QMimeData>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cout<<boolalpha;
list<string> ls;
cout<<(ls.begin() != ls.end())<<"\n";
QStringList qsl;
cout<<(qsl.begin() != qsl.end())<<"\n";
QMimeData qme;
cout<<(qme.formats().begin() != qme.formats().end())<<"\n";
cout<<"OMG! is it empty? -> "<<qme.formats().empty()<<"\n";
return a.exec();
}
The output is something like :
false
false
true
OMG! is it empty? -> true
Until or unless I take an rvalue reference I cant decide what is happening internally!
I really need a solution to use it with range based for loops, not Qt's foreach!
P.S. I dont want to copy it to avoid O(n).
Looking at the docs, there's no guarantee QMimeData class keeps QStringList of supported formats (http://doc.qt.io/qt-4.8/qmimedata.html#formats) as a field.
The source code supports that (Qt5.4/Src/qtbase/src/corelib/kernel/qmimedata.cpp:593):
QStringList QMimeData::formats() const
{
Q_D(const QMimeData);
QStringList list;
for (int i=0; i<d->dataList.size(); i++)
list += d->dataList.at(i).format;
return list;
}
Therefore this list is constructed on every call to formats(). Farther calls to it will always yield a separate container.
Since you do need to preserve it to traverse it, I'd recommend keeping a local copy of it. Do note that C++11 allows for it to be moved constructed (or in fact - optimized even better).
I am using the qUncompress of Qt and head to a problem I cant find more information to solve it.
Here is my code:
#include <QCoreApplication>
#include <QByteArray>
#include <QFile>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile f("/user/XXXXX/home/AgeRegression"); // hided
if (f.exists())
qDebug() << "File exists";
else
qDebug() << "Missing file";
f.open(QIODevice::ReadOnly);
QByteArray qb = f.readAll();
qb = qUncompress(qb);
qDebug()<<"Successfully";
const char *qt_version = qVersion();
qDebug()<< QString(qt_version);
return a.exec();
}
Here is the output:
File exists
qUncompress: Z_DATA_ERROR: Input data is corrupted
Successfully
"5.3.2"
From the documentation of Qt(you can find here):
Note: If you want to use this function to uncompress external data that was compressed using zlib, you first need to prepend a four byte header to the byte array containing the data. The header must contain the expected length (in bytes) of the uncompressed data, expressed as an unsigned, big-endian, 32-bit integer.
So what exactly should I do here? Do I have to find the length of uncompressed data (is there a way? I just have compressed data.)? An example would be appreciated.
qUncompress is not a general-purpose decompression function. It should only be used with data compressed with qCompress.
If your data was compressed using something other than qCompress, you must decompress it in the same way - using zlib directly, using an external utility, etc.
By using qUncompress like you do, you're relying on an implementation detail that may change at any moment. Don't do that. Simply assume that qCompress is a black box and uses an alien compressor implementation that nobody else does.