change fopen to stream - c++

I have the these code:
FILE *fp;
_wfopen_s(&fp, m_file, L"rb")
and
FILE *wmp
_wfopen_s(&wmp, s_file, L"wb")
I want to know how can I change above code to ofstream or ifstream, I know I can do something like this "outfile.open("junk.dat", ios::binary | ios::out);" with ofstream, But how I can put "s_file" and "&wmp" in ofstream?

First of all, if you want to continue using wide characters you should be using std::wofstream and std::wifstream.
Secondly, you don't use a FILE* at all, so no &wmp anywhere. The object you define is the file which you use to read from or write to. So you can have something like
std::wofstream wmp(s_file, wios::out | wios::binary);
if (wmp)
{
// Here you have an open output stream, write wide characters to it
wmp << L"Hello world\n"; // Writes a string to the file
// Write some binary data to the file
wmp.write(reinterpret_cast<wchar_t*>(some_data),
size_of_some_data_in_bytes / sizeof(wchar_t));
// The division is needed, as `write` write in units of `wchar_t`, not bytes
// This is problematic if some of the data you want to write isn't an even
// multiple of `sizeof(wchar_t)`
// And so on...
// Finally when done, close the file
wmp.close();
}
Note that if you are not writing strings to the file, but only raw binary data then I suggest you use plain std::ofstream instead, as you won't have to think in units of wchar_t and can just think in units of "bytes".
If you want to learn more this is an excellent reference about the C++ I/O classes.

Related

How do I change the value of a variable in an object with file handling?

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.

Why some data in binary file is shown as it is and other is shown in a strange way

I have code, which writes vector of such structures to a binary file:
struct reader{
char name[50];
int card_num;
char title[100];
}
Everything works actually fine but when I, for example, write to file structure {One,1,One} and open .txt file, where it is stored, I see this:
One ММММММММММММММММММММММММММММММММММММММММММММММММ One ММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММММ
So I was asked why is it displayed so, what it depends on, but I could'nt give a good answer to that question
EDITED:
Added code which I use to write to file
void Write_to_File(vector<reader>& vec){
cin.clear(); // clearing
fflush(stdin);// input stream
const char* pointer = reinterpret_cast<const char*>(&vec[0]);
size_t bytes = vec.size() * sizeof(vec[0]);
fstream f("D:\\temp.txt", ios::out);
f.close();
ofstream file("D:\\temp.txt", ios::in | ios::binary);
file.write(pointer, bytes);
file.close();
remove("D:\\lab.txt");
rename("D:\\temp.txt", "D:\\lab.txt");
cout << "\n*** Successfully written data ***\n\n";
}
P.S. When I read from file everything is ok
You write 154 octets in a file, only One and One are char, so your text editor try to read char but get mostly garbage. You write binary, you should not expect to have something readable.
Why some data in binary file is shown as it is and other is shown in a strange way
It seems that you are trying to read the binary data as if it contained character encoded data. Some of it does - but not all. Perhaps this is why you think that it seems strange. Other than that, the output seems perfectly reasonable.
why is it displayed so
Because that is the textual representation of the data that the object contains in the character encoding that your reader uses.
what it depends on
It depends on the values that you have initialized the memory to have. For example the first character is displayed as O because you have initialized name[0] with the value 'O'. Some of the data is padding between members that can not be initialized directly. What the value of those bytes depends on is unspecified.

File writing and appending in Binary mode not working

I am trying to append into file in binary mode but the logic below is not working.
For Pdf files,file is getting corrupted and for text files, it is adding some junk data in addition to my file contents.
My variable m_strReceivedMessage is of type std::string.
std::ofstream out(file, std::ios::binary | std::ios_base::app );
int i = sizeof(m_strReceivedMessage);
if (out.is_open()) {
// out.write(m_strReceivedMessage.c_str(), m_strReceivedMessage.size());
//out << m_strReceivedMessage;
out.write(reinterpret_cast<char *>(&m_strReceivedMessage), m_strReceivedMessage.size());
}
You're printing the memory of the std::string object, rather than the character buffer that it contains. To get a pointer to the character buffer, see the data() member function. Hint: The fact that you need to cast std::string* using reinterpret_cast<char*> is a dead giveaway that you're doing something very wrong.
Also, I'm not familiar with the PDF spec, but I suspect that it may possibly contain nul bytes. And depending on how you get your std::string, it's possible you may have missed any content after the first nul. std::vector<char> would be more appropriate way to store binary data.

Using QFile made istringstream as binary input (for libpng)

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.

fstream >> int failing?

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.