C++ Reading Unsigned Char from File Stream

C++ reading unsigned char from file stream

C++ does require the implementation only to provide explicit specializations for two versions of character traits:

std::char_traits<char>
std::char_traits<wchar_t>

The streams and strings use those traits to figure out a variety of things, like the EOF value, comparison of a range of characters, widening of a character to an int, and such stuff.

If you instantiate a stream like

std::basic_ifstream<unsigned char>

You have to make sure that there is a corresponding character trait specialization that the stream can use and that this specialization does do useful things. In addition, streams use facets to do actual formatting and reading of numbers. Likewise you have to provide specializations of those too manually. The standard doesn't even require the implementation to have a complete definition of the primary template. So you could aswell get a compile error:

error: specialization std::char_traits could not be instantiated.

I would use ifstream instead (which is a basic_ifstream<char>) and then go and read into a vector<char>. When interpreting the data in the vector, you can still convert them to unsigned char later.

reading/writing unsigned char array from/to file using filestream

The typecast is required because there are no istream or ostream methods for unsigned char.

By the way, in your functions you may want to return the actual bytes written or read (otherwise it's redundant since it is passed in.)

Use std::istream::gcount to get the characters read.

Reading unsigned char from .txt file using fread give different values

fread is for reading raw inputs. As your file is formatted text, use the following:

int nums[SIZE];
int count = 0;
while( fscanf(fin, "%d", nums + count) == 1 ) {
if(++count == SIZE) break; /* More than expected numbers in file */
}

Later you can print using:

for(i = 0; i < count; i++) {
printf("%d ", nums[i]);
}

fscanf is one way to read formatted input from files. You can use malloc, walking pointers as shown in your original code snippet or as per your requirements.

several different ways to read unsigned char from file

For the first part, the constructor also expects a file name. For example,

ifstream input("myfile.dat", ios::in | ios::binary);

I believe you can omit the ios::in, as it is the default for ifstream.

And for the second part, istream::read expects a char* pointer (or some equivalent type). After reading the data, you can cast the elements to unsigned char*.

How to output unsigned char to a text file in c?

I'd suggest to use function fwrite to write binary data to a file; obviously the solution works for arrays of SIZE==1 as well:

int main() {
#define SIZE 10

unsigned char a[SIZE] = {1, 2, 3, 4, 5, 0, 1, 2, 3, 4 };
FILE *f1 = fopen("file.bin", "wb");
if (f1) {
size_t r1 = fwrite(a, sizeof a[0], SIZE, f1);
printf("wrote %zu elements out of %d requested\n", r1, SIZE);
fclose(f1);
}
}

Read values from unsigned char bytestream in C++

So 'reading' a byte array just means extracting the bytes from the positions in the byte array where you know your data is stored. Then you just need to do the appropriate bit manipulations to handle the endianess. So for example, filecode would be this

filecode = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];

and version would be this

version = bytes[13] | (bytes[14] << 8) | (bytes[15] << 16) | (bytes[16] << 24);

(An offset of 13 for the version seems a bit odd, I'm just going on what you stated above).

LPSTREAM Read entire Stream contents into unsigned char* array

I'm confused about what I need to put in the second parameter of lpSrc->Read().

The answer is in the documentation:

ISequentialStream::Read method

pv [out]

A pointer to the buffer which the stream data is read into.

cb [in]

The number of bytes of data to read from the stream object.

pcbRead [out]

A pointer to a ULONG variable that receives the actual number of bytes read from the stream object.

You have to specify the number of bytes you want to read from the stream into your buffer.

I want to read the ENTIRE file into my unsigned char* (byte*) array:

That means you have to know how many bytes are available in the stream in the first place. You get that from the IStream::Stat() method. Then you have to allocate your rawData buffer to that size before you can then read data into the buffer.

Try something like this:

#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)(-1))
#endif

unsigned char* rawData;
LPSTREAM lpSrc = NULL;
HRESULT hrRet = STG_E_INVALIDPARAMETER;

TRY
{
USES_CONVERSION;
hrRet = pStg->GetStg()->OpenStream(
CT2COLE(szStream),
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0,
&lpSrc);

if (hrRet == S_OK)
{
STATSTG stat;
hrRet = lpSrc->Stat(&stat, STATFLAG_NONAME);
if (hrRet == S_OK)
{
if (stat.cbSize.QuadPart > SIZE_MAX)
{
hrRet = HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
}
else
{
size_t size = (size_t) stat.cbSize.QuadPart;

rawData = malloc(size);
if (!rawData)
{
hrRet = E_OUTOFMEMORY;
}
else
{
unsigned char *ptr = rawData;
size_t sizeLeft = size;

while (sizeLeft != 0)
{
ULONG ul;
hrRet = lpSrc->Read(ptr, (sizeLeft >= MAXDWORD) ? MAXDWORD : (DWORD) sizeLeft, &ul);
if (FAILED(hrRet) || (ul == 0)) break;
ptr += ul;
sizeLeft -= ul;
}

if (SUCCEEDED(hrRet))
{
if (sizeLeft != 0) size -= sizeLeft;
// use rawData up to size number of bytes as needed...
}

free(rawData);
}
}
}

lpSrc->Release();
}
}
CATCH_ALL(e)
{
hrRet = E_UNEXPECTED;
}
END_CATCH_ALL

Does a byte oriented FILE stream contain `char`s or `unsigned char`s?

It doesn't really matter. The standard use unsigned char at some chosen place because it allows precise formulation at those places:

  • fgetc is specified to return a unsigned char converted to an int so that one knows that the result is positive or null excepted when it is EOF (and thus there is no confusion possible between EOF and a valid char, confusion which is cause of bugs when one store directly the result of fgetc in a char without checking for EOF beforehand).

  • fputc is specified to take an int and convert it to an unsigned char because this conversion is well specified. If you aren't careful, formulation not using unsigned char could make UB a sequence like

    int c = fgetc(stdin);
    if (c != EOF)
    fputc(c, stdout);

with signed char for negative chars.

ifstream::read not reading unsigned char, even with reinterpret_cast

[Updated] This should work:

int pix[3]; // not an unsigned char
...
ifs >> pix[0] >> pix[1] >> pix[2];

instead of:

ifs.read(reinterpret_cast<char *>(pix), 3);

Like you do for width and height?

ifs >> w >> h >> max;


Related Topics



Leave a reply



Submit