QTextStream and std out - c++

I have the code:
QTextStream out(mFileHandle);
out << (QTime::currentTime().toString(Qt::LocalDate) + " - ").toAscii();
out << "Something another";
std::cout << "Data: \n";
std::cout << out.string();
out.flush();
It writes to file but after 'Data:' I get '0', why? How to send data to both streams?

It looks to me like you constructed your QTextStream out from a file handle. This means that it is going to write to that file.
The .string() method in QTextStream is only to access the QString used to construct it. In this case, it is zero, since you didn't use a string to construct it.
If you want to access the all the text that has been written to the QTextstream, you probably want to pass it a QByteArray as the constructor argument. This will make it write output to that QByteArray, rather than out to a file. Then, you can access the contents written to the stream through the QByteArray.

You would do somthing like that:
QByteArray outBytes;
QTextStream outStream(&outBytes);
//write something to outBytes via stream
outStream << (QTime::currentTime().toString(Qt::LocalDate) + " - ");
outStream << "Something another";
//construct QString from written bytes
std::cout << QString(outBytes).toStdString();

Related

Repeatedly write and read to/from QBuffer via QTextStream

I am trying to repeatedly write and read to/from a QBuffer object via QTextStream. First I construct both objects:
QBuffer b;
b.open(QIODevice::ReadWrite);
QTextStream s(&b);
// Setup text stream here
Then I write three different portions of information and read them back:
s << "Test" << 666 << endl << flush;
s.seek(0);
qDebug() << s.readAll();
s << "X" << endl << flush;
s.seek(0);
qDebug() << s.readAll();
s << "Test" << 777 << endl << flush;
s.seek(0);
qDebug() << s.readAll();
Of course I do not get the data portion I wrote immediately before, but the cumulated data:
"Test666\n"
"Test666\nX\n"
"Test666\nX\nTest777\n"
I could do adaptive seek calls to get the correct data but I do not want the QBuffer to grow infinitely.
I tried a s.reset() call between writes but the result is the same. Calling reset() or open()/close() directly on the buffer gives a crippled result (which is expected since the stream is bypassed):
"Test666\n"
"X\nst666\n"
"Test777\n"
I could probably build a new buffer for every cycle, open it and attach it to the stream but that is slow.
Is there a proper and fast solution for this use case?
You can access QBuffer's internal QByteArray storage directly with QBuffer::buffer() and then delete everything with QByteArray::clear(). Then manually seek() back to the start.
QBuffer b;
b.open(QIODevice::ReadWrite);
QTextStream s(&b);
s << "Test" << 666 << endl << flush;
s.seek(0);
qDebug() << s.readAll();
b.buffer().clear();
s.seek(0);
s << "X" << endl << flush;
s.seek(0);
qDebug() << s.readAll();
b.buffer().clear();
s.seek(0);
s << "Test" << 777 << endl << flush;
s.seek(0);
qDebug() << s.readAll();
"Test666\n"
"X\n"
"Test777\n"
QTextStream also has a constructor which takes a QByteArray directly and creates the QBuffer automatically, which may save a little code in this case.

tellg() returns -1 only for small files

I ran across a peculiar issue. Let's say I'm reading a file like this:
std::ifstream in("file.txt", std::ios::binary);
std::string text;
in.seekg(0, std::ios::end);
text.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&text[0], text.size());
The problem arises when the file contains less than 4 characters, i.e. "ab" or "abc", but works in other cases as intended, i.e. "abcd" or larger.
Why is tellg returning -1 for such a situation (ultimately causing my string to throw a std::length_error)?
Additional info:
I'm working with MSVC 15.5.3 (if not the latest, one of the more contemporary). Reproduced with GCC 5.1 as well.
This error doesn't occur with the equivalent C-style:
FILE* f = fopen("text.txt", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
EDIT:
failbit is set right before the first call to seekg, meaning opening the file failed? Why would that be the case for a file of less than 3 bytes...
After a few comments, it's clear that the ifstream constructor itself is failing in some way, as failbit is set even before the seekg call.
Since pretty much all I/O operation first construct a sentry object before proceeding, that will be why your operations are failing.
So I have a few suggestions.
First, use the full path name to your file just to ensure there's no possibility you're running it in a directory other than where the input file is.
Second, try the following complete program which works under g++ 5.4(a) to see if it exhibits the same problem (your code, while indicative, was not really complete).
#include <iostream>
#include <fstream>
int main() {
std::ifstream in("/full/path/to/file.txt", std::ios::binary);
std::cout << "after open, good=" << in.good() << ", bad=" << in.bad()
<< ", fail=" << in.fail() << ", eof=" << in.eof() << std::endl;
std::cout << "seekg returns " << in.seekg(0, std::ios::end) << std::endl;
std::cout << "after seek, good=" << in.good() << ", bad=" << in.bad()
<< ", fail=" << in.fail() << ", eof=" << in.eof() << std::endl;
std::cout << "tellg returns " << in.tellg() << std::endl;
std::cout << "after tell, good=" << in.good() << ", bad=" << in.bad()
<< ", fail=" << in.fail() << ", eof=" << in.eof() << std::endl;
}
Try this both with a two-byte and ten-byte file.
If none of that gives you any joy, Microsoft and/or GNU should be made aware of the issue. The former can be done here, the latter here.
Just for completeness, the only possibility that originally came to my mind was that the file, although three bytes long, is invalid in some way. This depends on the actual content so, if it is just abc, you can safely ignore this.
What I was thinking is something along the lines of a Unicode file with two byte BOM and the first byte of a multi-byte Unicode code point (e.g., UTF-16), or the first three bytes of of UTF-8 four-byte code point.
However, that seems incredibly unlikely if you're opening it in binary mode, so you can probably safely ignore it.
(a) For what it's worth, the only way I could get this to have failbit set after the open was to delete the file. Even using an empty file did not exhibit the problem you're describing.

Qt QFile return non existent but still opens and writes to file

I have this file which is located in my C drive, I know it exists. When I access it with QFile.exists() it returns false, however it still opens the file and writes to it, I just cant read it. I've been working on this for a while and cannot find a solution, any suggestions are appreciated.
QFile tmpfile("C:/file.txt");
QString tmpcontent;
if(!QFile::exists("C:/file.txt"))
qDebug() << "File not found"; // This is outputted
if (tmpfile.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
QTextStream stream(&tmpfile);
stream << "test"; //this is written
tmpcontent = tmpfile.readAll(); // this returns nothing
}
If file is not exist it will be created by open because you do it in write mode.
readAll function return all remaining data from device, since you just write something you are currently at the end of a file, and there is no data, try to seek( 0 ) to return to the beginnig of a file and then use readAll.
qDebug() << "File exists: " << QFile::exists("text.txt");
QFile test( "text.txt" );
if ( test.open( QIODevice::ReadWrite | QIODevice::Truncate ) ){
QTextStream str( &test );
str << "Test string";
qDebug() << str.readAll();
str.seek( 0 );
qDebug() << str.readAll();
test.close();
}else{
qDebug() << "Fail to open file";
}
As I can see from your code you need that file as a temporary, in such case I suggest to use QTemporaryFile, it will be created in temp directory (I belive there will be no problem with permissions), with unique name and will be auto deleted in object dtor.

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()
}

How can I capture data which will be sent to stdout in c++?

how can I capture data which will be sent to the stdout in c++?
I found here:
// This can be an ofstream as well or any other ostream
std::stringstream buffer;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer or any other ostream
std::cout.rdbuf(buffer.rdbuf());
std::cout << "Hello!";
// When done redirect cout to its old self
std::cout.rdbuf(sbuf);
std::cout << "STD data: \n";
std::cout << buffer.get();
And this doesn't work. 'Hello' still outputs before 'STD data:', and buffer.get() returns '-1'. What's wrong?
Write:
std::cout << buffer.str(); //not buffer.get();
Now its working : http://ideone.com/W8mW8
By the way, std::stringstream::get() returns std::istream. See this :
http://www.cplusplus.com/reference/iostream/istream/get/
Recall that std::stringstream derives from std::istream. So don't get confused. :-)