Nick
Nick

Reputation: 11384

How do I set the number of bytes read by ifstream get()?

I'm trying to parse MIDI, which needs to be read 8 bits (one byte) at a time. On my system(*), ifs.get() seems to be grabbing 32 bits at a time.

std::ifstream ifs;
ifs.open(FileName, std::fstream::in | std::ios::binary);

std::cout << "size:: " << sizeof(ifs.get()) <<std::endl; // returns 4

Is it possible to simply specify the number of bytes per read so ifs.get() gets only one byte (8 bits) at a time?

The reason why I believe ifs.get() is returning more than 8 bits is because:

uint16_t nReadByte = 0;
nReadByte = ifs.get();
std::cout << std::hex << nReadByte <<std::endl;

Produces results like:

3e,28,0,42,28,0,3b,28

But if I set the variable size to 8 bits I get bizarre characters:

uint8_t nReadByte = 0;
nReadByte = ifs.get();            
std::cout << std::hex << nReadByte <<std::endl;

@,,,,.,4,p,s,2,. (These don't seem to be rendering here correctly, but sometimes they look like the letters ETX and CAN in a single glyph.

Upvotes: 1

Views: 864

Answers (3)

mediocrevegetable1
mediocrevegetable1

Reputation: 4207

On my system(*), ifs.get() seems to be grabbing 32 bits at a time.

Your example proving this is incorrect. First of all, the ifs.get() inside sizeof won't even get evaluated, because expressions in sizeof don't get evaluated. Second of all, std::ifstream is an alias for std::basic_ifstream<char>, and ifs.get() taking no parameters will indeed return one character of the std::basic_ifstream's character type. Since this is char in your case, if CHAR_BIT (defined in <climits>) is defined as 8 on your system then it will indeed read 8 bits at a time.

The reason sizeof(ifs.get()) is 4 is because ifs.get()'s return value is std::ifstream::traits_type::int_type which is int (the reason the return value is not char is because it may need to return std::ifstream::traits_type::eof() as well which may not fit in char). And on your system, sizeof (int) is 4.

The reason output looks different for uint16_t and uint8_t seems to be that for uint16_t it's actually printing the bytes as hex whereas for uint8_t it seems to be printing as characters (uint8_t is an alias for unsigned char and ostreams overload operator<<(unsigned char) to print characters), which is why some are not showing and the output generally looks different.

Upvotes: 4

eerorika
eerorika

Reputation: 238351

How do I set the number of bytes read by ifstream get()?

The second parameter is the number of bytes to read, if you give a buffer as the first targument.

On my system(*), ifs.get() seems to be grabbing 32 bits at a time.

You're mistaken. The nullary overload reads exactly one byte. The return type is int so that it can represent, besides all possible values of a char, also EOF (End Of File) which is a special value outside the range of char that is returned if the stream has reached the end.

uint16_t nReadByte = 0;
nReadByte = ifs.get();
std::cout << std::hex << nReadByte <<std::endl;

uint16_t is an alias of unsigned short or unsigned int neither of which are character types. When you insert a non-character integer into a character stream, it will be represented as a number corresponding to its numeric value; in this case modified by the std::hex manipulator.

But if I set the variable size to 8 bits I get bizarre characters:

uint8_t nReadByte = 0;
nReadByte = ifs.get();            
std::cout << std::hex << nReadByte <<std::endl;

uint8_t is an alias of unsigned char which is a character type. When you insert a character into a character stream, it will not be represented by a number corresponding to its numeric value. Instead, it will be represented by a symbol corresponding to the value in the current character encoding. Some values aren't visible symbols, but rather control characters that affect how a terminal behaves for example.

If you want to stream the numeric value of a character object, then you must convert to another integer type such as unsigned int.

(These don't seem to be rendering here correctly

When used in contexts where they aren't meaningful, control characters may helpfully be shown with a visible symbol, but not all fonts have such place-holders and websites often remove them when sainiting user input.

Upvotes: 2

kenash0625
kenash0625

Reputation: 697

it seemes ifstream::read is better.

from https://www.cplusplus.com/reference/istream/istream/read/

istream& read (char* s, streamsize n);

Read block of data

Extracts n characters from the stream and stores them in the array pointed to by s.

Upvotes: 1

Related Questions