Reading a file char by char not working as expected [duplicate] - c++

This question already has answers here:
Why does reading of this stream from a binary file stop at the 0x1A character? [duplicate]
(1 answer)
C reading (from stdin) stops at 0x1a character
(5 answers)
Closed 19 days ago.
i made this little code to read char by char the 120 first bytes of a binary file :
int main(){
string filename("kodim23.qoi");
ifstream image_file(filename); //open file
if (!image_file.is_open()) { //check if file is open
cerr << "Could not open the file - '"
<< filename << "'" << endl;
return EXIT_FAILURE;
}
for (int q = 0;q<120;q++) //read char by char and display them as int
{
cout << q << " : ";
cout << int(image_file.get()) << endl;
}
image_file.close(); //close file
return 0;
}
I get an expected output for q in range 0 to 114 and then just -1 forever (i tried to increase q it's always -1) :
console output.
I tried to open the file with frhed (an hexadecimal editor) to check what happens at offset 115, but there is nothing weird : frhed output.
As you can see at offset 114 there is 0x54 (84), so my program is working as expected and then at offset 115 there is 0x1a (90) and my program output is -1...
Do you know what could be wrong ?

Related

How is the file offset advanced by fstream::read? [duplicate]

This question already has answers here:
tellg() function give wrong size of file?
(4 answers)
Closed 3 years ago.
#include <fstream>
#include <iostream>
int main(int argc, char * argv [])
{
std::ifstream f{ "test.syp" };
std::cout << f.tellg() << '\n';
char buffer[4];
f.read(buffer, 4);
std::cout << f.gcount() << '\n';
std::cout << f.tellg() << '\n';
}
When I execute the above code, I get the following output:
0
4
20
If I change ifstream to fstream, I get the same thing except that the last number is 21.
I would expect the last number to be 4 in both instances. Why isn't it?
Edit: I get the expected result if I open the file with std::ios::binary; it must be a quirk of text-mode
f.gcount returns the number of characters read by the last unformatted input operation (in this case, f.read()).
f.tellg() returns an input position indicator; that's an opaque value that has meaning to seekg(), but its numeric value isn't meaningful to user programs.

Not reading all of file

I'm trying to use a simple decryption algorithm to decrypt some files. The code I have so far will work for the most part, but stop reading after a few hundred bytes and export what it has.
Example, I have a .X file, it's 14.7KB. I run it through the program and it comes out as 643 bytes.
The current code is here: http://pastebin.com/aNNjYTzg
Since the code formatting for this site is driving me insane...
I just added in the algorithm to existing code, so most of it is not used.
EDIT:
cout << "Enter the name of your file to " << encrypt_decrypt[choice-1] << ": ";
cin >> filename;
in.open(filename);
getline(in,buffer);
void encryptdecrypt(const string buffer,const char map[],int len,string& newbuffer)
{
int i=0;
char t;
char code;
for (i=0;i<buffer.length();i++)
{
t=buffer[i];
(t += 251 - ((i * 14) & 255));
cout << "Buffer length: " << buffer.length() << endl;
cout << "newbuffer length: " << newbuffer.length() << endl;
newbuffer.push_back(t);
}
newbuffer.push_back('\n');
}
out << newbuffer;
EDITx2:
Reads the whole file, but only beginning parts are decrypted.
<?xml version="1.0"?>
<Materi
+"Òû%÷*&$'
ëÐ!ÐÎ&"# ëÐ"!Ý "
Ü"ÐÎÝ컸
So, given that the result of (t += 251 - ((i * 14) & 255)) is any value in the character range, you will need to read and write the file as a "binary" file, or the content won't "work".
This means that you need to use stream::read to read a block of data and stream::write to write data to the output file, and when you open the file, you need to supply ifstream::binary and ofstream::binary respecitvely as the mode.
A text input (when you don't specify binary in the mode) will interpret certain input bytes as end of file (stopping the input) and other input bytes as newline characters (which, if you use getline will be ignored on input). Since in your encrypted form, you don't use those characters to mean exactly those things, you should not use text-based input (the encrypted file isn't a text file).

Can not read enough data from a file when the file has enough data c++

I have this code in c++ ( it is after I did some tests to see why I can not read enough data from file, so it is not final code and I am looking to find why I am getting this result)
size_t readSize=629312;
_rawImageFile.seekg(0,ifstream::end);
size_t s=_rawImageFile.tellg();
char *buffer=(char*) malloc(readSize);
_rawImageFile.seekg(0);
int p=_rawImageFile.tellg();
_rawImageFile.read(buffer,readSize);
size_t extracted = _rawImageFile.gcount();
cout << "s="<< s <<endl;
cout << "p="<< p <<endl;
cout << "readsize="<< readSize<<endl;
cout << "extracted="<< extracted <<endl;
cout << "eof ="<< _rawImageFile.eofbit<<endl;
cout << "fail="<< _rawImageFile.failbit <<endl;
The output is as follow:
s=3493940224
p=0
readsize=629312
extracted=2085
eof =1
fail=2
As you can see the file size is 3493940224 and I am at the start of file (p=0) and I am trying to read 629312 bytes, but I can only read 2085?
What is the problem with this code? I did open this file in other methods and read some data out of it, but am using seekg to move pointer to the beginning of file.
The file was opened as binary.
edit 1
To find a solution, I put all code inside a function and here is it:
_config=config;
ifstream t_rawImageFile;
t_rawImageFile.open(rawImageFileName,std::ifstream::in || std::ios::binary );
t_rawImageFile.seekg (0);
size_t readSize=629312;
t_rawImageFile.seekg(0,ifstream::end);
size_t s=t_rawImageFile.tellg();
char *buffer=(char*) malloc(readSize);
t_rawImageFile.seekg(0);
size_t p=t_rawImageFile.tellg();
t_rawImageFile.read(buffer,readSize);
size_t x=t_rawImageFile.tellg();
size_t extracted = t_rawImageFile.gcount();
cout << "s="<< s <<endl;
cout << "p="<< p <<endl;
cout << "x="<< x <<endl;
cout << "readsize="<< readSize<<endl;
cout << "extracted="<< extracted <<endl;
cout << "eof ="<< t_rawImageFile.eof()<<endl;
cout << "fail="<< t_rawImageFile.fail() <<endl;
and the result is:
s=3493940224
p=0
x=4294967295
readsize=629312
extracted=2085
eof =1
fail=1
Interestingly, after read the file pointer moves to a very big value. is it possible that since the file size is very big, the application fails?
edit 2
Tested the same code with another file. the result is as follow:
s=2993007872
p=0
x=4294967295
readsize=629312
extracted=1859
eof =1
fail=1
What I can read from this test is that:
after read the file pointer moves to a big number which is always the same. The amount that it reads depend on file (!).
edit 3
After changing the size_t to fstream::pos_type the result is as follow:
s=2993007872
p=0
x=-1
readsize=629312
extracted=1859
eof =1
fail=1
Why file position goes to -1 after a read?
t_rawImageFile.open(rawImageFileName, std::ifstream::in || std::ios::binary );
...does not open the file in binary mode. Since || is the lazy or operator and std::ifstream::in is non zero, the whole expression has the value 1.
t_rawImageFile.open(rawImageFileName, std::ifstream::in | std::ios::binary );
...will surely work better.
You don't show the part where your file is being opened, but I'm pretty sure it is missing ios::binary to make sure the C runtime code doesn't interpret CTRL-Z (or CTRL-D) as end of file.
Change this line:
t_rawImageFile.open(rawImageFileName,std::ifstream::in || std::ios::binary );
into this:
t_rawImageFile.open(rawImageFileName,std::ifstream::in | std::ios::binary );

Assign last number of a text file to a variable C++

I am doing a program that outputs a list of prime numbers with fstream.
I have this so far:
int export_list (int lim = 50)
{
int x;
last_in_txt = ????????????; // assigns last number on txt
ofstream file ("Primes.txt" , ios::app);
if (file.is_open()) // if it opens correctly
{
for (x = last_in_txt ; x < lim ; x++)
{
if (check_prime (x)) // returns 1 when x is prime, returns 0 when not
{
file<< x << " ";
}
}
cout << "Done!" << endl << pressenter;
cin.get();
}
else
{
cout << "Unable to open file" << endl << pressenter;
cin.get();
}
return(0);
}
So, as you can see, this should append a list of prime numbers to Primes.txt, starting with the prime 1234547.
Primes.txt looks like this:
2 3 5 7 11 13 17 19 23 29 31 37 (...) 1234543 1234547
My question is how do I assign 1234547 (which is the last number of the txt) to the variable last_in_txt?
Other (not so important) question:
Should I save the numbers the way I'm currently doing, or should I store each number in a separate line?
One simple way: keep reading and assign until the whole file is read.
For example,
int last_in_txt = 0;
{
ifstream infile("Prime.txt");
int k;
while(infile >> k) {
last_in_txt = k;
}
}
// Now last_in_txt is assigned properly, and Prime.txt is closed
This works well no matter the numbers in Prime.txt are separated by space characters (' ') or by newline characters ('\n').
My suggestion is that you write using binary format into the text file(using wb in C). In this case you will know how many bytes does the last number occupy and you will be able to use seekg and tellg to get it. If you use plain text format you will have to read char by char from the end and this is more error-prone and also slower.

Read binary file c++

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
It's a good practice to use unsigned char to use with binary data.
The character randomly selected might not be displayed properly in the console window due to the limitations in the fonts supported. Also you can verify the same thing by printing it in hexadecimal and open the same file in a hex editor to verify it. Please don't forget to delete the memory allocated after use.