Any idea why the following would fail?
std::fstream i(L"C:/testlog.txt", std::ios::binary | std::ios::in);
int test = 0;
i >> test;
fail() is returning true. The file exists and is opened.
I checked
i._Filebuffer._Myfile._ptr
and it is pointer to a buffer of the file so I don't see why it is failing.
You're opening the file in binary mode. The extraction operators were meant to be used with text files. Simply leave out the std::ios::binary flag to open the file in text mode.
If you actually do have a binary file, use the read() function instead.
Edit: I tested it too, and indeed it seems to work. I got this from CPlusPlus.com, where it says:
In binary files, to input and output data with the extraction and insertion operators (<< and >>) and functions like getline is not efficient, since we do not need to format any data, and data may not use the separation codes used by text files to separate elements (like space, newline, etc...).
Together with the description of ios::binary, which simply states "Consider stream as binary rather than text.", I'm utterly confused now. This answer is turning into a question of its own...
The following:
#include <fstream>
#include <iostream>
using namespace std
int main() {
std::fstream i("int.dat" , std::ios::binary | std::ios::in);
int test = 0;
if ( i >> test ) {
cout << "ok" << endl;
}
}
prints "ok" when given a file containing the characters "123". Please post a similar short test that illustrates your code failing.
Related
I am working on a project with oop and file handling and I need a changeQuantity() method where the name of the item and a number(positive or negative) is passed. I want to change the quantity with this method and write the changes to the file.
My Object:
class Item(){
int itemId, quantity;
char title[25], type[10];
float price;
public:
void changeQuantity(char*, int);
};
The changeQuantity() method I am using:
void Item::changeQuantity(char* name, int quan){
fstream file;
file.open("filename.txt", ios::in | ios::out);
//after finding the object to work on
this->quantity += quan;
file.seekp(file.tellp() - sizeof(*this));
file.write((char*)this, sizeof(*this));
}
I tried with this method but it messes up the entire text file. How can I change only the quantity variable and write that change to the file without affecting anything else?????
Any kind of help would be greatly appreciated. Thank You.
PS: What I want to do here is only change the value of the quantity variable stored in the object which is stored in the txt file. The code that I am using messes the txt file.
I removed parameters except the file name from file.open() method. As fstream already has default parameters ios::in | ios::out, I removed that and it worked the way I wanted it to. But it does not work 100% of the time. It still repeats the problem sometimes and I haven't been able to find that out why.
It seems like you are mixing apples and oranges. You read something from a text file of size *this; but you read it into the binary storage of your object, and in binary mode. When it is written out, it is still in the binary format of your object. Ways to do it right:
Open the file in text mode, and read and write everything with, say gets & puts (insecure and error prone). Translate every number from text to binary when reading it in.
It is better to read them into std::string variables; as it is more powerful and less error prone. The classic C++ way to do it is e.g. the example from Input/output with files:
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << line << '\n';
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
You would need to adapt it to read and translate (e.g. from text number format to a variable) each member of your object. I don't know of a way to mass read e.g. lines of text in a text file into an object's members. Once it is in binary format and properly read into your object, you can write our objects out to a binary file like that; but note: they won't be of fixed size, so you will need to write the size of the object out first, and then the object itself; and read the size of the object in and then the object itself.
In short, you are using a binary file access method, when e.g. your ints are text instead of probably 32-bit binaries, and your strings are are \n or \n\r instead of null terminated. Typical ways to handle text input and output of objects are to have one text line for each member, and translate them one at a time; or to read and write them as CSV or JSON - again one at a time for each member; and then looping through the file.
BTW: It is considered bad form to use using std; as in this example. To keep things in the std namespace from interfering with your variables and routines, it is better to use using std::string; etc.; for each thing you want to access from the std namespace.
I'm currently working on this program for a class in my university. I've tried multiple approach with no success. I'm pretty sure it's just a conversion problem, but I want to understand the differences.
What the program supposed to do : We're to create a program that ask the user for two filenames. One will be an input and another will be an output. The program is supposed to read the input and write the line to the output while until the end of the input file is not reached.
My Code :
#include <iostream>
#include <fstream> //included for read/writing files
#include <string> //Included this for getline to read the file
using namespace std;
int main() {
ifstream infile; // Stream to read from input file
ofstream outfile; // Stream to write to output file
char inputfilename[80], outputfilename[80]; //declaring two character arrays to save the file names.
string text;
cout << "What is the name of your input file (text.txt)" ; // Prompting user for input file name
cin >> (inputfilename); // Getting input file
infile.open(inputfilename, ios::in); // Opening the input file.
cout << "What is the name of your output file" ; // Prompting user for output file name
cin >> (outputfilename);
outfile.open(outputfilename, ios::out);
if(!infile) { // If cannot open file
cout << "There was an error opening your file!" ;
return 1;
}
if (!outfile) {
cout << "There was an error opening your file!" ;
return 1;
}
while (infile.eof()==0) {
fgets(text, 80, infile);
fprintf(outfile,"%d. %s\n", text);
}
infile.close(); // Closing input file
outfile.close(); // Closing output file
return 0;
}
What I've tried : I didn't know if it was being affected by how I opened the file. I previously tried.
ifstream infile;
ofstream outfile;
char text, inputfilename[80], outputfilename[80]; <----- 1
cout << "What is the name of your input file (text.txt)" ;
gets(inputfilename); <----- 2
infile.open(inputfilename);
cout << "What is the name of your output file" ;
gets(outputfilename); <----- 2
outfile.open(outputfilename);
1) I switched char I previous tried
char text
char text[80]
char *text[80]
2) Would switching how getting the file name change anything in the while loop(I previous tried getline and gets)? Additionally the "f" in front of fgets/fprints/etc are always associated with a file stream?
Note: My teacher gave us the hint.
"Suppose you read a line from the input file into a string variable called str using the following statement: fgets(str, 80, infile);You can add a line number and save the line with the line number to the output file using the same statement using: fprintf(outfile,"%d. %s\n",Next_line_number++, str);"
from this I tried :
while (infile.eof()==0) {
fgets(text, 80, infile);
fprintf(outfile,"%d. %s\n", text);
}
as well as
while (infile.eof()==0) {
fgets(text, 80, infile);
fputs(text, outFile);
}
and
while (infile.eof()==0) {
getline(infile, text);
fprintf(outfile,"%d. %s\n", text);
}
I also tried making a long and using that to increment the line number. I'm fairly new to programming; if any of the methods I'm using our dated please let me know (on some sites they were saying fgets is dated and not supported on cx11 or some version of C++)! I want to understand the concepts vs just get the programming running. Should note Lines 34-35 are where my code is always erroring out and it's
cannot convert 'std::__cxx11::string {aka std::__cxx11::basic_string}' to 'char*' for argument '1' to 'char* fgets(char*, int, FILE*)'
I figured I was getting this because it has a pointer to the file and I'm asking the user vs having the file declared in the program. This is causing a conversion that causing my error.
fgets(text, 80, infile);
fgets() is a C library function, that expects a char * as its first parameter. It knows absolutely nothing about any C++ class, and not just std::string that you are passing as the first parameter. Neither does fgets() has any clue about the C++ std::ifstream class you're attempting to pass to it as its third parameter. And that's exactly what your compiler's error message states.
You are randomly mixing up C and C++ code, which results in repeated confusion.
char inputfilename[80], outputfilename[80];
You should also use std::strings, instead of arbitrary-sized C style arrays, here.
while (infile.eof()==0) {
This is always a bug, and read this linked article for more information.
fprintf(outfile,"%d. %s\n", text);
Again: fprintf is also a C library function, that knows absolutely nothing about C++ classes like std::string and std::ofstream. In either case, this is a bug because this string has placeholders for two parameters, an integer, %d, and C style string, %s; and you're giving just one parameter here, text. In the event that you were writing C instead of C++ code, this would not've worked either, but that's mostly academic. This is a C++ program, and this C library function has no business doing anything here, in the first place.
When you are reading from a std::ifstream:
You can use std::getline to read an entire line of text into a std::string
Alternatively you can use the >> formatted extraction operator
Or you can use various methods of the std::ifstream object to read from the file and into a suitable buffer
These alternatives are not equivalent (otherwise what would be the point?) and they do different things, and the right one to use depends on what the requirements are.
Similarly, to write to a std::ofstream you can use:
The << formatted output operator.
Various methods of the std::ofstream object itself.
And, in some advanced situations you can take advantage of the iterator library, and implement reading and writing using input and output iterators, too.
The correct approach depends on the individual situation. For more information on how to read and write from files in C++ using these approaches, see any good C++ book. Whichever C++ book actually advised you to use fgets() to read from a std::ifstream and into a std::string: throw it away, and get a better book, from the list linked above. If this is just what you found in some program somewhere on the Internet -- you can't learn C++ this way, by piecing together different parts of different programs, and hope that the results work. To fix all of your compilation errors: remove all that C code that knows absolutely nothing about C++, and replace it with proper C++ code, using any of the options I outlined above, using the examples from the C++ books linked above, as a reference.
I am attempting to use libpng in order to read a png from
a Qt resource. The catch: The class doing the reading
should not have any dependencies of Qt.
In a first step, reading http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/#CustomRead I already succeeded in writing a function
read_png(istream& in)
I also succeeded in passing a plain old ifstream
ifstream in("abs_path_to_png/icon.png");
to read_png(..) and having it successfully reading the png. But how to get
a (preferably platform independent) istream from a Qt resource? Performance
is no great issue so I initially came up with
bool Io_Qt::get_istringstream_from_QFile(QFile& qfile, istringstream& iss)
{
// [.. Some checking for existence and the file being open ..]
QString qs(qfile.readAll());
iss.str(qs.toStdString());
// I also tried: QByteArray arr(qfile.readAll()); iss.str(arr.data());
return qfile.isOpen();
}
// Someplace else iss and qfile are created like this:
istringstream iss(std::stringstream::in | std::stringstream::binary);
QFile qfile(":/res/icon.png");
qfile.open(QIODevice::ReadOnly);
This in fact yields an iss that is, at first glance, looking good, when saying
cout << "'" << iss.str().c_str() << "'" << endl;
I get
'�PNG
'
There appears to be some whitespace issue though. For
ifstream in("abs_path_to_png/icon.png");
char c;
cout << "'";
for (int j=0;j<8;j++)
{
in >> c;
cout << c;
}
cout << "'" << endl;
yields
'�PNG'
and while the latter works the former variation ultimately leads the libpng checking function png_sig_cmp(..) into rejecting my png as invalid. My first reflex is about "binary". However:
istringstream iss(std::stringstream::in | std::stringstream::binary); feels right.
QIODevice::ReadOnly does not appear to have a binary partner.
Do you see what I missed?
You're working with the streams like they're text data with lexical extraction operators. Check out ios::binary as well as the read and write methods which are appropriate when working with a binary stream.
I would forgo operator<< and operator>> outright in your case in favor of read and write. Use ostream::write to write the byte array data returned from QIODevice::readAll() to transfer its contents to your temporary stringstream, e.g., and use ostream::read in your tests to validate its contents.
A good test case to make sure you transferred properly is to write a test where you read the contents from a QFile, use ostream::write to transfer it to an binary output file stream (ofstream), and then try to load it up in an image software to see if it's okay. Then swap your file stream with a stringstream and pass it to libpng when you have that working.
As Ike says, it seems indeed to be about the differences between
text-centered operators '>>', '<<' and stuff like '.str(..)' as opposed
to binary-centered commands like '.read', and '.write'. Plus it is
about initializing the streams correctly. When I finally got the program
to do what I wanted the gospel went something like this:
First I used a plain stringstream alongside the QFile:
// Explicitly setting flags should at least contain ::in and ::out
// stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary)
// However, the default constructor is perfectly fine.
stringstream ss;
QFile qfile(":/res/icon.png");
qfile.open(QIODevice::ReadOnly);
This I passed to my function which now looks like this:
bool Io_Qt::get_stringstream_from_QFile(QFile& qfile, stringstream& ss)
{
// [.. some sanity checks..]
QDataStream in(&qfile);
uint len = qfile.size();
char* c = (char*)malloc(len*sizeof(char));
in.readRawData(c,len);
ss.write(c,len);
free (c);
return true;
}
This stream was filled, and had the right size. Especially since
.write(..) writes the required number of characters regardless
of how many zeros are within the data. My biggest problem was
my being loath to have both std::stringstream::in AND
std::stringstream::out activated at the same time because the
combination seemed somewhat wacky to me. Yet both are needed.
However, I found I may skip std::stringstream::binary.
But since it does not seem to do any harm I like to
keep it for good luck. Feel free to comment on this superstition though! :-)
A more clean, less C-ish, more Qt/C++ -ish version can be:
QFile file(filePath);
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
std::istringstream iss(data.toStdString());
now use iss, in my case this was for libTIFF:
TIFF* tif = TIFFStreamOpen("MemTIFF", &iss);
// ...
Also, for PNGs you can now follow your already posted article, since std::istringstream is of type std::istream.
Note, this solution involves full loading of the file data into memory.
I read about fstream, etc., a while ago. It says that ifstream is used to read data from a file, while ofstream is used to write data. I want to know that, what is the essence of using ifstream/ofstream if you can just use cin.getline() to fetch the data and cout << to print those?
ifstream: Stream class to read from files
ofstream: Stream class to write to files
Now what is a file?
Files are resources for storing information. For example, a text file.
Now, let's look at an example which explains ofstream.
Look at the following code:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
Here, we are writing something to a file. Writing information you can say.
Now, what is the difference between cin/cout and ifstream/ofstream?
cin is an object of class istream and cout is an object of class ostream. And in fact, we can use our file streams the same way we are already used to using cin and cout, with the only difference being that we have to associate these streams with physical files. Just think that cin/cout is a part of istream/ostream that is used for standard input/output.
Hope it helps a bit.
For more information, you can look at this link:
Input/output with files.
Ifstream()
ifstream() is used to input the file.
ifstream() is fstream() object it is used to input the single character or string or set of character to a file
it inherits the function get(), getline(), read(), etc...
Ofstream()
ofstream() is used to output the file
ofstream() is fstream() object it is used to output the single character or string or set of character from a file
it inherits the function put(), write(), etc...
According to the reference, if I use ifstream infile ( "test.txt" , ifstream::in ); it will Allow input operations on the stream. But what are some of the examples of the "input operations"?
Is ifstream infile ( "test.txt" , ifstream::in | ifstream::binary ); the right syntax to use multiple flags?
Will it make a difference if I change ifstream:: to iso:: ?
Thank you
According to the reference, if I use ifstream infile ( "test.txt" ,
ifstream::in ); it will Allow input
operations on the stream. But what are
some of the examples of the "input
operations"?
Reading from a file which would mean everything an input stream can support. See istream member functions. Typically, you can do both formatted (using >>) and unformatted reads (using read). Remember that ifstream is a specialization of the basic_ifstream template for char type. Depending on your needs, say to read UTF-16 encoded file, you may have to use a different specialization (wifstream) or even use a special locale (read this to know more about locales).
Is ifstream infile ( "test.txt" , ifstream::in | ifstream::binary );
the right syntax to use multiple
flags?
Yes.
Will it make a difference if I change ifstream:: to iso:: ?
No.
Stream operations are extraction << and insertion >>. When you do the following assuming
file is of fstream type:
file << 5 << 6.5 << "Hello World!"; // insertion of data (output)
file >> x >> y >> str; // exaction of data (input)
You could also, deal with the stream as a binary stream. In that case, it doesn't really look like a "stream" of data but that gives you random access to the data. In some cases you can't use the binary mode, especially if your data is not available like a network stream. Insertion and Extraction, are the two main operations on streams.
ifstream is created as an input stream by default. So, std::ios::in is redundant in this case. You are using the flags correctly.
all streams inherit from ios. So, the flags are available in both places, you can either retrieve them from ios directly or from fstream.