Writing long stream of characters to text file QT C++ - c++

I am trying to write a program that will create a text file and write a stream of characters that I read from a serial port. I am just trying to understand how I can get the code to continuously write the data and not overwrite the previously written data because I will need it to keep every character sent. I wrote this code as a test but I can't get it to continuously write the text. It writes it once and then stops.
#include <QFile>
#include <QTextStream>
int main() {
int test = 0;
while(test < 2){
QString filename = "Data.txt";
QFile file(filename);
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << "one thing to test" << endl;
test++;
}
}
}
Anyone have any suggestions?
-Thanks

By default, opening with QIODevice::ReadWrite will truncate the file on write. According to the documentation, QIODevice::Append will open the file for writing at the end of the file.
If you really want to both read and write, you could QIODevice::seek() to the end of the file before writing.

Related

I can't get the ofstream function to work

Hello and sorry if the answer is clear to those out there. I am still fairly new to programming and ask for some guidance.
This function should write just one of the three string parameters it takes in to the txt file I have already generated. When I run the program the function seems to work fine and the cout statement shows the info is in the string and does get passes successfully. The issue is after running the program I go to check the txt file and find it is still blank.
I am using C++17 on visual studio professional 2015.
void AddNewMagicItem(const std::string & ItemKey,
const std::string & ItemDescription,
const std::string &filename)
{
const char* ItemKeyName = ItemKey.c_str();
const char* ItemDescriptionBody = ItemDescription.c_str();
const char* FileToAddItemTo = filename.c_str();
std::ofstream AddingItem(FileToAddItemTo);
std::ifstream FileCheck(FileToAddItemTo);
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
if (_access(FileToAddItemTo, 0) == 0)
{
if (FileCheck.is_open())
{
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
}
AddingItem.close(); // not sure these are necessary
FileCheck.close(); //not sure these are necessary
}
This should print out a message onto a .txt file when you pass a string into the ItemKey parameter.
Thank you very much for your help and again please forgive me as I am also new to stackoverflow and might have made some mistakes in formatting this question or not being clear enough.
ADD ON: Thank you everyone who has answered this question and for all your help. I appreciate the help and would like to personally thank you all for your help, comments, and input on this topic. May your code compile every time and may your code reviews always be commented.
As mentioned by previous commenters/answerers, your code can be simplified by letting the destructor of the ofstream object close the file for you, and by refraining from using the c_str() conversion function.
This code seems to do what you wanted, on GCC v8 at least:
#include <string>
#include <fstream>
#include <iostream>
void AddNewMagicItem(const std::string& ItemKey,
const std::string& ItemDescription,
const std::string& fileName)
{
std::ofstream AddingItem{fileName, std::ios::app};
if (AddingItem) { // if file successfully opened
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
else {
std::cerr << "Could not open file " << fileName << std::endl;
}
// implicit close of AddingItem file handle here
}
int main(int argc, char* argv[])
{
std::string outputFileName{"foobar.txt"};
std::string desc{"Description"};
// use implicit conversion of "key*" C strings to std::string objects:
AddNewMagicItem("key1", desc, outputFileName);
AddNewMagicItem("key2", desc, outputFileName);
AddNewMagicItem("key3", desc, outputFileName);
return 0;
}
Main Problem
std::ofstream AddingItem(FileToAddItemTo);
opened the file. Opening it again with
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
caused the stream to fail.
Solution
Move the open modes into the constructor (std::ofstream AddingItem(FileToAddItemTo, std::ios::app);) and remove the manual open.
Note that only the app open mode is needed. ofstream implies the out mode is already set.
Note: If the user does not have access to the file, the file cannot be opened. There is no need to test for this separately. I find testing for an open file followed by a call to perror or a similar target-specific call to provide details on the cause of the failure to be a useful feature.
Note that there are several different states the stream could be in and is_open is sort of off to the side. You want to check all of them to make sure an IO transaction succeeded. In this case the file is open, so if is_open is all you check, you miss the failbit. A common related bug when reading is only testing for EOF and winding up in a loop of failed reads that will never reach the end of the file (or reading past the end of the file by checking too soon).
AddingItem << ItemKey;
becomes
if (!(AddingItem << ItemKey))
{
//handle failure
}
Sometimes you will need better granularity to determine exactly what happened in order to properly handle the error. Check the state bits and possibly perror and target-specific
diagnostics as above.
Side Problem
Opening a file for simultaneous read and write with multiple fstreams is not recommended. The different streams will provide different buffered views of the same file resulting in instability.
Attempting to read and write the same file through a single ostream can be done, but it is exceptionally difficult to get right. The standard rule of thumb is read the file into memory and close the file, edit the memory, and the open the file, write the memory, close the file. Keep the in-memory copy of the file if possible so that you do not have to reread the file.
If you need to be certain a file was written correctly, write the file and then read it back, parse it, and verify that the information is correct. While verifying, do not allow the file to be written again. Don't try to multithread this.
Details
Here's a little example to show what went wrong and where.
#include <iostream>
#include <fstream>
int main()
{
std::ofstream AddingItem("test");
if (AddingItem.is_open()) // test file is open
{
std::cout << "open";
}
if (AddingItem) // test stream is writable
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
AddingItem.open("test", std::ios::app);
if (AddingItem.is_open())
{
std::cout << "open";
}
if (AddingItem)
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
}
Assuming the working directory is valid and the user has permissions to write to test, we will see that the program output is
open and writable
open and NOT writable
This shows that
std::ofstream AddingItem("test");
opened the file and that
AddingItem.open("test", std::ios::app);
left the file open, but put the stream in a non-writable error state to force you to deal with the potential logic error of trying to have two files open in the same stream at the same time. Basically it's saying, "I'm sorry Dave, I'm afraid I can't do that." without Undefined Behaviour or the full Hal 9000 bloodbath.
Unfortunately to get this message, you have to look at the correct error bits. In this case I looked at all of them with if (AddingItem).
As a complement of the already given question comments:
If you want to write data into a file, I do not understand why you have used a std::ifstream. Only std::ofstream is needed.
You can write data into a file this way:
const std::string file_path("../tmp_test/file_test.txt"); // path to the file
std::string content_to_write("Something\n"); // content to be written in the file
std::ofstream file_s(file_path, std::ios::app); // construct and open the ostream in appending mode
if(file_s) // if the stream is successfully open
{
file_s << content_to_write; // write data
file_s.close(); // close the file (or you can also let the file_s destructor do it for you at the end of the block)
}
else
std::cout << "Fail to open: " << file_path << std::endl; // write an error message
As you said being quite new to programming, I have explicitly commented each line to make it more understandable.
I hope it helps.
EDIT:
For more explanation, you tried to open the file 3 times (twice in writing mode and once in reading mode). This is the cause of your problems. You only need to open the file once in writing mode.
Morever, checking that the input stream is open will not tell you if the output stream is open too. Keep in mind that you open a file stream. If you want to check if it is properly open, you have to check it over the related object, not over another one.

How to save .txt file in C++? [duplicate]

This question already has answers here:
How to append text to a text file in C++?
(5 answers)
Closed 7 years ago.
I have created a code writing stuff in a .txt file and read from it. But if I close the program and start to write again, it deletes the old text and overwrites it with the new one.
Is there a way to not overwrite existed data?
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void check() {
string text;
ifstream file;
file.open("test.txt");
getline(file, text);
if (text == "") {
cout << "There's no data in file" << endl;
} else {
cout << "File contains:" << endl;
cout << text << endl;
}
}
int main() {
check();
string text;
ofstream file;
file.open("test.txt");
cout << "Type some text" << endl;
getline(cin, text);
file << text;
return 0;
}
You need to open the file in 'append' mode like in the following example
#include <fstream>
int main() {
std::ofstream outfile;
outfile.open("yourfile.txt", std::ios_base::app);//std::ios_base::app
outfile << "your data";
return 0;
}
You can read here about fstream flagshttp://www.cplusplus.com/reference/fstream/fstream/open/
Keep in mind that in c++ there are several ways to open, save, and read text data to and from a file. It sounds like you opened with with a function (and its options) to always create a new file. One thing you could do is run your program and then close the program and use a text editor to open the file to verify whether the text you wrote to the file is actually there. Also take a look at the code that was provided by Evyatar. That example uses ofstream which allows options for read, write, and append. The "app" parameter tells the program to keep what is already in the file and append any new data that you add in the next run. When testing files where you are appending, be careful you don't end up with a huge file you did not intend to have so large.
In the code that you posted in your revised question, be sure to close the file in your check function and at the end of the program. It is possible to get things hung up if you don't. As a precaution, I usually close a file prior to opening it, just to be sure it is closed with no problems. This practice comes form my days programming in BASIC where it was an essential. If the program crashed, you couldn't open it again until you got it closed. Also, of course, close the file after you're done with it and before the end of the program. Then, when you open it in main, open with the append option.
Please, insert code for next time. If you open file in write mode, than is normal that every time you write to file, the content of file is changed. You need to use append mode.

C++ edit a binary file with another

Solved! thanks all of you very much. My day has been made!(well morning, its 4am)
I'm trying to write a program in C++ that opens a .dat file in binary and replaces the first 1840 hex characters with that of another .dat file, while leaving the remaining hex values of the first .dat file the same. I have spent about 12 hours on this today and have had little success. I am a beginner programmer, I have taken one semester worth of c++ courses and we did not get to streams.
(it opens a file and everything, but deletes every thing after the new values have been added)
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>
#include <cstring>
using namespace std;
int main (){
string filename;
long size;
char* memblock;
cout << " Enter a file to be modded by Mod.dat ";
cin >> filename;
ofstream infile ( filename ,std::ofstream::binary);
//filename: the file that will be opened and changed)
ifstream modFile ("Mod.dat", ifstream::binary);
// (mod.dat is the file that i get the first 1840 hex values from)
modFile.seekg (0,modFile.end);
size = modFile.tellg();
memblock = new char [size];
modFile.seekg (0, ios::beg);
modFile.read (memblock, size);
infile.write(memblock, 1840);
modFile.close();
infile.close();
cout << endl;
return 0;
}
Any help would be greatly appreciated, I hope there is some simple way to do this.
Solved! thanks all of you very much. My day has been made!(well morning, its 4am)
Edit:
You can modidy your file in place with something like :
std::fstream s(my_file_path, std::ios_base::binary);
s.seekp(position_of_data_to_overwrite, std::ios_base::beg);
s.write(my_data, size_of_data_to_overwrite);
std::fstream will not truncate your input file as std::ofstream does.
The other solution is to not use the same file for reading and writing. Use three files :
One for the output file.
One for the First input file.
One for the second input file.
fstream infile ( filename ,std::ofstream::binary); does not keeps the contents of the original file. Everything you write will erase the contents of the file.
Thus, you should:
open the output file
open the "Mod" file, read the first 1840 bytes from the first file, write them into the output file.
open the "main input file" file, move the cursor to 1840, read the remaining data and write it to the output file.
Depending on the "main input file" size, you may want to buffer you read/write operation.
My preferred fix, although Matthieu Rouget's fix does indeed work, is to just add ofstreeam::in to the opening of the input file:
ofstream infile ( filename.c_str(), std::ofstream::binary | ofstream::in);
(I had to use c_str() in my build, as glibc in my version doesn't take std::string as input).
I tested this on my local system (it took a while to realize that mod.dat is actually "Mod.dat"!)
It is probably a good idea to also check that the files actually opened, so something like this after ofstream infile line:
if (!infile)
{
cout << "Couldn't open " << filename << endl;
}
and similar for the modfile line.
And since you go through the effort of figuring out what the first part of the modfile size is, I would suggest that you also USE that for the writing of the file.

c++ text decoder decoding more than asked for

Im working on a text file decoder along with an encoder, they work off of two different text files. The decoder prints the decoded message underneath the encoded message but it also prints a bunch of other stuff as well. How do i fix this
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
ifstream fin; // input file
string line;
ofstream fout;
//open output file
fout.open("secret.txt", ios::app);
if (!fout.good()) throw "I/O error";
// open input file
fin.open("secret.txt");
if (!fin.good()) throw "I/O error";
// read input file, decode, display to console
while (fin.good()) {
getline(fin, line);
for (int i = 0; i < line.length(); i++) // for each char in the string...
line[i]--; // bump the ASCII code down by 1
fout << line << endl; // display on screen
}
// close file
fin.close();
return 0;
}
the text file from the encoder reads
Uftujoh234
Ifmmp!nz!obnf!jt!cpc
Dmptfe!
Uftujoh
which decodes to
Testing123
Hello my name is bob
Closed
Testing
this is all the extra stuff it also prints in the text file
Sdrshmf012
Gdkknlxm`ldhrana
Bknrdc
Sdrshmf
Rcqrgle/01
Fcjjmkwl_kcgq`m`
Ajmqcb
Rcqrgle
Qbpqfkd./0
Ebiiljvk^jbfp_l_
#ilpba
Qbpqfkd
Paopejc-./
Dahhkiuj]iaeo^k^
?hkoa`
Paopejc
O`nodib,-.
C`ggjhti\h`dn]j]
>gjn`_
O`nodib
N_mncha+,-
B_ffigsh[g_cm\i\
=fim_^
N_mncha
M^lmbg`*+,
A^eeh
The extra data you see is actually valid output from decoding the data in "secret.txt".
I'm not sure if this is what you want, but are you aware that you are reading and writing to the same file each time you run your application?
You'll append more and more "decoded" data to the file, and therefore you get the extra output you are referring to.
Also, there is an issue with your while-loop.
fin.good () will remain true until some of the error bits has been set inside of fin, though it will enter the loop one time too much since you should check to state of the stream immediately after your call to getline (fin, ...).
Currently the reading will fail but you will still process the "unread" data.
std::getline will return the stream object, and since a std::istream (as well as std::ostream) implicitly can be converted to a boolean to check it's current state you should use that as your loop-condition.
Change your loop into something as the below and see if that solves your problem.
while (getline (fin, line))
{
for (int i = 0; i < line.length(); i++) // for each char in the string...
line[i]--; // bump the ASCII code down by 1
fout << line << endl; // display on screen
}
The extra stuff isn't extra. You are writing data into the same file you are reading, so what you do is:
write line
read line
You are renencoding the data you already encoded.

Creating/writing into a new file in Qt

I am trying to write into a file and if the file doesn't exist create it. I have searched on the internet and nothing worked for me.
My code looks currently like this:
QString filename="Data.txt";
QFile file( filename );
if ( file.open(QIODevice::ReadWrite) )
{
QTextStream stream( &file );
stream << "something" << endl;
}
If I create a text file called Data in the directory, it remains empty. If I don't create anything it doesn't create the file either.
I don't know what to do with this, this isn't the first way in which I tried to create/write into a file and none of the ways worked.
Thanks for your answers.
That is weird, everything looks fine, are you sure it does not work for you? Because this main surely works for me, so I would look somewhere else for the source of your problem.
#include <QFile>
#include <QTextStream>
int main()
{
QString filename = "Data.txt";
QFile file(filename);
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << "something" << endl;
}
}
The code you provided is also almost the same as the one provided in detailed description of QTextStream so I am pretty sure, that the problem is elsewhere :)
Also note, that the file is not called Data but Data.txt and should be created/located in the directory from which the program was run (not necessarily the one where the executable is located).
Are you sure you're in the right directory?
Opening a file without a full path will open it in the current working directory. In most cases this is not what you want. Try changing the first line to
QString filename="c:\\Data.txt" or
QString filename="c:/Data.txt"
and see if the file is created in c:\
#include <QFile>
#include <QCoreApplication>
#include <QTextStream>
int main(int argc, char *argv[])
{
// Create a new file
QFile file("out.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << "This file is generated by Qt\n";
// optional, as QFile destructor will already do it:
file.close();
//this would normally start the event loop, but is not needed for this
//minimal example:
//return app.exec();
return 0;
}
Your code is perfectly fine, you are just not looking at the right location to find your file. Since you haven't provided absolute path, your file will be created relative to the current working folder (more precisely in the current working folder in your case).
Your current working folder is set by Qt Creator. Go to Projects >> Your selected build >> Press the 'Run' button (next to 'Build) and you will see what it is on this page which of course you can change as well.
It can happen that the cause is not that you don't find the right directory. For example, you can read from the file (even without absolute path) but it seems you cannot write into it.
In that case, it might be that you program exits before the writing can be finished.
If your program uses an event loop (like with a GUI application, e.g. QMainWindow) it's not a problem. However, if your program exits immediately after writing to the file, you should flush the text stream, closing the file is not always enough (and it's unnecessary, as it is closed in the destructor).
stream << "something" << endl;
stream.flush();
This guarantees that the changes are committed to the file before the program continues from this instruction.
The problem seems to be that the QFile is destructed before the QTextStream. So, even if the stream is flushed in the QTextStream destructor, it's too late, as the file is already closed.
QFile file("test.txt");
/*
*If file does not exist, it will be created
*/
if (!file.open(QIODevice::ReadOnly | QIODevice::Text | QIODevice::ReadWrite))
{
qDebug() << "FAILED TO CREATE FILE / FILE DOES NOT EXIST";
}
/*for Reading line by line from text file*/
while (!file.atEnd()) {
QByteArray line = file.readLine();
qDebug() << "read output - " << line;
}
/*for writing line by line to text file */
if (file.open(QIODevice::ReadWrite))
{
QTextStream stream(&file);
stream << "1_XYZ"<<endl;
stream << "2_XYZ"<<endl;
}