C++ Ifstream reads too much? - c++

I'm trying to read a file and output the contents. Everything works fine, I can see the contents but it seems to add about 14 empty bytes at the end. Does anyone know whats wrong with this code?
int length;
char * html;
ifstream is;
is.open ("index.html");
is.seekg (0, ios::end);
length = is.tellg();
is.seekg (0, ios::beg);
html = new char [length];
is.read(html, length);
is.close();
cout << html;
delete[] html;

You didn't put a null terminator on your char array. It's not ifstream reading too much, cout just doesn't know when to stop printing without the null terminator.
If you want to read an entire file, this is much easier:
std::ostringstream oss;
ifstream fin("index.html");
oss << fin.rdbuf();
std::string html = oss.str();
std::cout << html;

That is because html is not null-terminated string, and std::cout keeps printing character until it finds \0, or it may crash your program
Do this:
html = new char [length +1 ];
is.read(html, length);
html[length] = '\0'; // put null at the end
is.close();
cout << html;
Or, you can do this:
cout.write(html, length);
cout.write will stop printing exactly after length number of chars.

Related

How to find string in exe?

is
find
function can't work with exe? i try to find wstring in an exe. it always not match. but if i create a txt and copy binary inside exe to txt and it can find it.
std::wifstream file(L"D:/file.exe", std::ios::binary);
if (file.is_open())
{
file.seekg(0, file.end);
std::streamoff length = file.tellg();
file.seekg(0, file.beg);
wchar_t *buffer = new wchar_t[length];
file.read(buffer, length);
std::wstring sFile;
sFile = buffer;
size_t index = sFile.find(L"Something");
if (index != std::string::npos) std::cout << "It's found";
file.close();
delete[] buffer;
}
else
{
std::cout << "It's not open";
}
The executable probably has a number of 0 bytes (i.e. 0x00) early on in the file. When you do sFile = buffer; it assumes that buffer is a C-style string that ends in a 0 byte. So sFile will only contain the bytes up to that point.
To fix it you should put the whole buffer into the string:
std::wstring sFile(buffer, length); // Directly using the constructor, or
sFile.assign(buffer, length); // after construction
Just change
std::wstring sFile;
sFile = buffer;
to
std::wstring sFile(buffer, buffer+length);
When you assigning char-buffer to wstring object, the length of the string is determined by the first null character. So, the first 0x00 byte containing in your file denotes the end of string.

C++ istream::read causes undefined behaviour

I using the following code to copy n character from binary file to char* variable :
std::ifstream is ("write.abc", std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
std::cout << "length of buffer: "<<strlen(buffer) <<endl;
std::cout << "Content of buffer: "<<buffer <<endl;
.......
The content of my file:
This is the result of compilation:
My question is the following: I'm waiting to have:
length of buffer: 13
Content of buffer: abcdefghjklmn
Can some one, please, help me to interpret the result?
Your buffer is not terminated - you need to allocate an extra char and set it to '\0', otherwise it's just an unterminated C string, so strlen will most likely return an invalid value, and attempting to print the string will typically produce garbage.
char * buffer = new char [length + 1]; // <<< allocate space for `length`
// characters + terminator
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
buffer[length] = '\0'; // <<< terminate C-style string
Note that using proper C++-style std::strings instead of old school C-style char * strings avoids this and other common problems, and is generally simpler and a lot more robust. If you're reading binary data rather than text, then consider using std::vector<unsigned char>.
Please note that this is not answering the question. It is a followup to a comment
One solution is to "store" the buffer as a [begin, end) range instead of null terminated C string. This has a big advantage over null terminate string - it can be used with STL algorithms without calling strlen(...) to find end element.
Following some examples:
std::stringstream is("some text\n");
if (is)
{
// get length of file:
is.seekg (0, is.end);
auto length = is.tellg();
is.seekg (0, is.beg);
char* begin = new char [length];
char* end = begin + length;
std::cout<<"Reading "<<length<<" characters...\n";
// read data as a block:
is.read (begin,length);
//print the data:
std::copy(begin, end, std::ostream_iterator<char>(std::cout));
//print the data backwards:
std::copy(std::reverse_iterator<char*>(end), std::reverse_iterator<char*>(begin), std::ostream_iterator<char>(std::cout));
std::cout<<std::endl;
//create string from data:
std::string str(begin, end);
std::cout<<str;
//sum the characters
auto sum = std::accumulate(begin, end, 0);
std::cout<<sum<<std::endl;
//make them uppercase
std::transform(begin, end, begin, toupper);
std::copy(begin, end, std::ostream_iterator<char>(std::cout));
}

How can I assign a std::string from a char * [duplicate]

This question already has answers here:
How do I read an entire file into a std::string in C++?
(23 answers)
Closed 8 years ago.
This may be trivial, but I'm new to C++ and an getting confused here.
I have the method:
bool load_database_file( const std::string& filename, std::string& contents ) {
std::ifstream is (filename, std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = (int)is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer, length);
if (is)
std::cout << "all characters read successfully.";
else
std::cout << "error: only " << is.gcount() << " could be read";
is.close();
// ...buffer contains the entire file...
std::string str(buffer);
contents = str;
delete[] buffer;
}
return true ;
}
where I would like to read a file and assign it's contents to contents so that it can be read by the calling function.
My issue is that after this function is run, I see that only the first character of buffer was copied to contents.
How can I copy/convert the entire contents of buffer (a char *) to contents (a std::string).
std::string str(buffer);
Should be:
std::string str(buffer, buffer+length);
Otherwise, how can the constructor know how many bytes to allocate/copy?
By the way, your code is needlessly clumsy. Why not read directly into the string's buffer rather than using a separate buffer that you have to allocate and free just to hold the data before you allocate another buffer?

Read unknown symbols when read a content of file

As in the title, when read a content of file i find it reads unknown symbols with the content.
The code:
char *buff = NULL;
size_t size = 0;
ifstream file("c:\\file.txt", ios::out);
if(!file){
cout << "File does not open." << endl;
}
file.seekg(0, file.end);
size = file.tellg();
file.seekg(0, file.beg);
buff = new char[size];
while(!file.eof()){
file.read(buff, size);
}
cout << buff << endl;
delete[] buff;
The file content:
Hello world!.
Thank you for help.
The result:
As you seen in the previous image, there are many unknowns symbols.
Why these symbols appear, what's wrong in my code ?
Your char array is not null terminated, either create the array with space for one extra null character (and set it to '\0')
buff = new char[size + 1];
buff[size] = '\0';
// Or simply
buff = new char[size + 1]{};
or even better avoid using raw pointers wherever possible, especially for character arrays used as strings.
while(!file.eof()) is an antipattern, don't use it except in very specific cases.
std::ifstream file("file.txt");
std::string buff{ // Use regular brackets if not C++11
std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>()
};
You can only use operator<<(const char *) for C-style strings. You can't use it for arbitrary chunks of bytes. How would it know where to stop?

Read from a simple encrypted file C++

I am trying to write a program which will output a XOR encrypted string to a file and will read this string and decrypt it back . To encrypt my string I have used a simple XOR Encryption : (thanks to Kyle W.Banks site)
string encryptDecrypt(string toEncrypt)
{
char key = 'K'; //Any char will work
string output = toEncrypt;
for (int i = 0; i < toEncrypt.size(); i++)
output[i] = toEncrypt[i] ^ key;
return output;
}
Then In my program I use the following code to write and then read the string :
string encrypted = encryptDecrypt("Some text");
cout << "Encrypted:" << encrypted << "\n";
ofstream myFile("test.txt");
myFile << encrypted;
// Read all the txt file in binary mode to obtain the txt file in one string
streampos size;
char * memblock;
ifstream file ("test.txt", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
}
//Convert the memblock into string and show the result of decrypted string
string result(memblock);
string decrypted = encryptDecrypt(result);
cout << "Decrypted:" << decrypted << "\n";
In result I have :
Encrypted : ,<.c%.;%
Decrypted : Õ52E65AD0
Maybe to save the file cause some problems into the byte saved so It can't retrieve the same byte when the program tried to read the string, but I'm not sure at all.
Best regards
Since you're not closing the output, there's a fair chance that your OS won't let you open the file for reading.
You're decrypting regardless of whether the file was successfully read.
If it wasn't successfully read, you'll have undefined behaviour due to memblock not being initialised - most likely getting a result constructed from random garbage data.
Once you get that fixed, you need to zero-terminate memblock to make it a "proper" C-style string.
Encryption with XOR is kind of dangerous. Assume your plain text contains the letter 'K', the encrypted string will contain a '\0' at this position. Your string will be cut off there.
Same thing for the other direction, you are reading the encrypted string. Converting the memory block to a string will result in a shorter string because std::string::string(const char*) will stop reading at '\0'.
Apart from that, memblock isn't initialized when the file could not be opened, so put the encryption part into the if (file.IsOpen()) clause.
As said by Zuppa it is dangerous to use it that way the string may terminate unexpectedly due to '\0'
you should post - calculate the length of the text you are dealing with it can be easily done by using stream.seekg(0,ios_base::end)
and you can use read and write functions to write or get the text from the file
ifstream file ("test.txt", ios::in|ios::binary|ios::ate);
file.seekg(0,ios::end);
int length=file.tellg();//length of the text in the file
file.seekg(0);
char *memblock=new char[length];
file.read(memblock,length);
you may consult this Simple xor encryption