i'm trying to ready a binary-file into a set of variables using the c++ std::ifstream class.
The following example works:
std::ifstream inFile;
inFile.open("example.bin");
uint8_t temp8;
uint16_t temp16;
inFile >> temp8;
inFile >> temp8;
But if i replace the last two lines with one line
inFile >> temp16;
nothing is read and inFile.fail() returns true.
Can anyone explain, why I can't read into a 16 bit variable?
The operator>> overload for reading uint16_t from istreams is a formatted input function, meaning does not read binary data, it reads a string and if necessary converts it to a number (e.g. using strtoul or similar).
As explained at http://en.cppreference.com/w/cpp/io/basic_istream
The class template basic_istream provides support for high level input operations on character streams. The supported operations include formatted input (e.g. integer values or whitespace-separated characters and characters strings) and unformatted input (e.g. raw characters and character arrays).
inFile >> temp16 tries to read a sequence of (usually) ASCII digits, up to the first non-digit character, then converts that sequence of digits to a number, and if it fits in uint16_t stores it in temp16. If you are reading from a binary file then the istream is probably not going to find a sequence of ASCII digits, so reading fails.
You need to use an unformatted input function to read 16 bits directly from the file without trying to interpret a string as a number, like:
inFile.read(reinterpret_cast<char*>(&temp16), 2);
The extraction of an integer from a stream with >> expects to find ascii numeric digits. If it doesn't find them, it sets the fail status.
If your uint16_t data is not by pure coincidence composed by two bytes, which the first appear to be between 0x30 and 0x39, it's doomed to fail. ANd if it would succed, it wouldn't be the values that you expect.
For binary data use:
inFile.read (&temp16, sizeof(temp16));
and of course, open the file with ios::binary mode.
Related
I'm trying to use std::cin after a while.
Using uint8_t or unsigned char:
unsigned char data;
std::cin >> std::dec >> data;
Whatever std::dec is used or not, I get the first ASCII character I type.
If I type 12, data is 0x31 not 12. Why can't it parse number until 255 to be stored in a char?
int data;
std::cin >> std::dec >> data;
gives correctly data=12/0xC not 0x31
Why?
Using char[N] with std::hex
char data[128];
std::cin >> std::hex >> data;
Also gets the ASCII characters instead of the hexadecimal.
Writting 0x010203040506... data is 0xFFFFFFFFF...
Isn't std::cin>>std::hex able to parse the string I type into hexadecimal automatically?
In short:
cin >> charVar scans a single character from stdin
cin >> intVar scans characters from stdin until a non-numeric character is entered
Explaining your observation:
A char variable can store a single ASCII character.
When you type 12, only the character 1 is scanned.
The ASCII code of the character 1 is 0x31.
std::dec and std::hex affect the format of integers.
But as far as the streaming operators are concerned, char and its variants (including uint8_t aren't integers, they're single characters. They will always read a single character, and never parse an integer.
That's just how these functions are defined. There is no way around it. If you want an integer with a limited range, first read into an int (or other integer type that is not a char variant), and then range-check afterwards. You can, if you want, cast it to a small type afterwards, but you probably shouldn't. char types are awkward to work with numerically.
Similarly, reading into an array of char reads a string. (Also, never do that without using setw() to limit the length to fit in the buffer you have. Better yet, use std::string instead.) That's just how it's defined.
So, I'm having some issues with my c++ code. I have the following code, but so far I can't get most of the data stored into the structured data type.
//structured data declaration
struct item
{
int itemCode;
char description[20];
float price;
};
And then the get code looks like this.
cout << setprecision(2) << fixed << showpoint;
ofstream salesFile ("Sales.txt");
ifstream stockFile ("Stock.txt");
for (counter = 0; counter < 9; counter++)
{
stockFile >> instock[counter].itemCode;
stockFile.getline (instock[counter].description, 20);
stockFile >> instock[counter].price;
}
The output should have looked like:
1234 "description here" 999.99
Quantity X
And this was the output:
1234 0.00
Quantity 5
If you have a file format that is of the form (for one entry)
1234
description here
999.99
(across multiple lines) then the explanation is simple
Th reading code in your loop, which does
stockFile >> instock[counter].itemCode;
stockFile.getline (instock[counter].description, 20);
stockFile >> instock[counter].price;
will work in this sequence
The value of instock[counter].itemCode will receive the value 1234. However (and this is important to understand) the newline after the 1234 will still be waiting in the stream to be read.
The call of getline() will encounter the newline, and return immediately. instock[counter].description will contain the string "".
The expression stockFile >> instock[counter].price will encounter the d in description. This cannot be interpreted as an integral value, so instock[counter].price will be unchanged.
Assuming some preceding code (which you haven't shown) sets instock[counter].price to 999.99 the above sequence of events will explain your output.
The real problem is that you are mixing styles of input on the one stream. In this case, mixing usage of streaming operators >> with use of line-oriented input (getline()). As per my description of the sequence above, different styles of input interact in different ways, because (as in this case) they behave differently when encountering a newline.
Some people will just tell you to skip over the newline after reading instock[counter].itemCode. That advice is flawed, since it doesn't cope well with changes (e.g. what happens if the file format changes to include an additional field on another line?, what happens if the file isn't "quite" in the expected format for some reason?).
The more general solution is to avoid mixing styles of input on the one stream. A common way would be to use getline() to read all data from the stream (i.e. not use >> to interact directly with stockFile). Then interpret/parse each string to find the information needed.
Incidentally, rather than using arrays of char to hold a string, try using the standard std::string (from standard header <string>). This has the advantage that std::string can adjust its length as needed. std::getline() also has an overload that can happily read to an std::string. Once data is read from your stream as an std::string, it can be interpreted as needed.
There are many ways of interpreting a string (e.g. to extract integral values from it). I'll leave finding an approach for that as an exercise - you will learn more by doing it yourself.
I am trying to read binary data from file using the following code:
std::ifstream fp;
fp.open("C:\\my_binary_data.dat", std::ios::binary);
std::istream_iterator<byte> start(fp), end;
std::vector<byte> tof(start, end);
fp.close();
The file has 401 bytes, but the tof vector is only 380 elements long, i.e. it stops reading before the end. The end is set to nullptr(?), thus the iterator reads until it reads a zero byte? The 380th byte is 109. What is the stop condition here? And how can I be sure it reads the whole file?
Using
fp.seekg (0, fp.end);
std::streamoff length = fp.tellg();
fp.seekg (1, fp.beg);
gives length=401
istream_iterator is an avatar of operator >>; it uses that operator to read from the stream. That is almost never what you want for reading binary data, because >> is a formatted input function. You could probably coerce it to do what you want by using manipulators such as noskipws on the stream, but it would still effectively remain a use of the wrong tool for the job.
If you want an iterator-based access to binary data in a stream, you might be better off using an istreambuf_iterator (which is guaranteed to work character by character) instead.
I am new to programming and I have this question. I have this file that I am opening
ifstream fin;
FILE * pFile;
pFile = fopen (fname,"r");
The file has 3 data each line. The first is an integer, the second is an alphabet and the third is an address(like computer memory address). How do I extract these line by line into 3 variables that I can process, and then repeat it with next line and so.
You should know that there are preferred C++ methods for manipulation of files over C stdio methods:
Using standard predefined streams: std::ofstream for output and std::ifstream for input.
Formatted/Unformatted I/O such as operator<<(), operator>>(), read() and write().
In-memory I/O for manipulation of extracted data.
What you need for this particular case is input stream functionality along with formatted input. The formatted input will be done through operator>>().
But before you get to that, you have to instantiate a file stream. Since you're using input, std::ifstream will be used:
std::ifstream in("your/path.txt");
The next thing to do is to create the three variables whose values you will extract into the stream. Since you know the types beforehand, the types you will need is an integer, character, and string respectively:
int num;
char letter;
std::string address;
The next thing to do is to use operator>>() to obtain the first valid value from the stream. The way it works is that the function analyses the type of the righthand operand and determines if the characters extracted from the file stream will create a valid value after parsing. When the stream hits whitespace, the new line character or the EOF (end-of-file) character (or a character that doesn't match that of the operand's type), extraction will stop.
What makes IOStreams powerful is that it allows chaining of expressions. So you are able to do this:
in >> num >> letter >> address;
which is equivalent to:
in >> num;
in >> letter;
in >> address;
This is all that is needed for this simple case. In more complex situations, loops and in-memory I/O might be needed for successful extractions.
I have a strings like this:
315c4eeaa8b5f8aaf9174145bf43e1784b8fa00dc71d885a804e5ee9fa40b16349c146fb778cdf2d3aff021dfff5
Is there a way to read it from file at once into string object keeping in mind that every 2 chars are hexadecimal representation of byte? I.e. I need a reading with conversion from hex to char.
UPDATE
Guys, please read carefully what I asked.
I'm able to write conversion functions and looping along a string.
BUT I need read a string of hex to a string of char at once.
No any looping. No conversions by hands.
Something like cin >> ...some string variable...
Thanks.
UPDATE2
Imagine I have the string "315c4eeaa8b5". I want to write something like cin >> string_var and get that string_var containing exactly the "'0x31','0x5c','0x4e','0xea','0xa8','0xb5'". Please note, this last is an ordinal std::string. I.e. 0x31,0x5c,etc are codes of chars.
Hope it makes thing clearer.
Either you code something up or you use something that already exits. If you are using C++ IO streams then I would suggest taking a look at Boost.IOStreams library and especially its Filtering Streams concept. You can use the tab expanding 2.2.5.2 input_filter tutorial example as a base for your hexadecimal input filter implementation.
You can use istream::opeartor>> with the std::hex manipulator to parse as hexadecimal:
ifstream in("...");
char buffer[3];
vector<char> chars;
while (in.read(buffer, 2))
{
buffer[2] = '\0';
char c;
istringstream(buffer) >> hex >> c;
chars.push_back(c);
}