I'm trying to read an image into a char array. Here is my try:
ifstream file ("htdocs/image.png", ios::in | ios::binary | ios::ate);
ifstream::pos_type fileSize;
char* fileContents;
if(file.is_open())
{
fileSize = file.tellg();
fileContents = new char[fileSize];
file.seekg(0, ios::beg);
if(!file.read(fileContents, fileSize))
{
cout << "fail to read" << endl;
}
file.close();
cout << "size: " << fileSize << endl;
cout << "sizeof: " << sizeof(fileContents) << endl;
cout << "length: " << strlen(fileContents) << endl;
cout << "random: " << fileContents[55] << endl;
cout << fileContents << endl;
}
And this is the output:
size: 1944
sizeof: 8
length: 8
random: ?
?PNG
Can anyone explain this to me? Is there an end-of-file char at position 8? This example was taken from cplusplus.com
Running Mac OS X and compiling with XCode.
Returns the size of the file. size of your image.png
is 1944 bytes
.
cout << "size: " << fileSize << endl;
Returns the sizeof(char*)
, which is 8
on your environment. Note that size of any pointer is always the same on any environment.
cout << "sizeof: " << sizeof(fileContents) << endl;
The file you are reading is a binary file so it might contain 0
as a valid data. When you use strlen
, it returns the length until a 0
is encountered, which in the case of your file is 8
.
cout << "length: " << strlen(fileContents) << endl;
Returns the character at the 56th location
(remember array indexing starts from 0) from start of file.
cout << "random: " << fileContents[55] << endl;
A suggestion:
Do remember to deallocate the dynamic memory allocation for fileContents
using:
delete[] fileContents;
if you don't, you will end up creating a memory leak.
fileSize - the number of bytes in the file.
sizeof( fileContents ) - returns the size of a char* pointer.
strlen( fileContents) - counts the number of characters until a character with a value of '0' is found. That is apparently after just 8 characters - since you are reading BINARY data this is not an unexpected result.
cout << fileContents - like strlen, cout writes out characters until one with a value of '0' is found. From the output it looks like some of the characters aren't printable.
Your example has some other issues - it doesn't free the memory used, for example. Here's a slightly more robust version:
vector< char > fileContents;
{
ifstream file("htdocs/image.png", ios::in | ios::binary | ios::ate);
if(!file.is_open())
throw runtime_error("couldn't open htdocs/image.png");
fileContents.resize(file.tellg());
file.seekg(0, ios::beg);
if(!file.read(&fileContents[ 0 ], fileContents.size()))
throw runtime_error("failed to read from htdocs/image.png");
}
cout << "size: " << fileContents.size() << endl;
cout << "data:" << endl;
for( unsigned i = 0; i != fileContents.size(); ++i )
{
if( i % 65 == 0 )
cout << L"\n';
cout << fileContents[ i ];
}
This answer of mine to another question should be exactly what you are looking for (especially the second part about reading it into a vector<char>
, which you should prefer to an array.
As for your output:
sizeof(fileContents)
return the size of a char *
, which is 8 on your system (64 bit I guess)strlen
stops at the first '\0'
, just as the output operator does.What do you expect? png files are binary so they may contain '\0'
character (character having numeric value 0) somewhere.
If you treat the png file contents as string ('\0' terminated array of characters
) and print it as string then it will stop after encountering the first '\0'
character.
So there is nothing wrong with the code, fileContents
is correctly contains the png file (with size 1944 bytes)
size: 1944 // the png is 1944 bytes
sizeof: 8 // sizeof(fileContents) is the sizeof a pointer (fileContents type is char*) which is 8 bytes
length: 8 // the 9th character in the png file is '\0' (numeric 0)
random: ? // the 56th character in the png file
?PNG // the 5th-8th character is not printable, the 9th character is '\0' so cout stop here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With