Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tellg() function give wrong size of file?

Tags:

c++

file

ifstream

I did a sample project to read a file into a buffer. When I use the tellg() function it gives me a larger value than the read function is actually read from the file. I think that there is a bug.

here is my code:

EDIT:

void read_file (const char* name, int *size , char*& buffer) {   ifstream file;    file.open(name,ios::in|ios::binary);   *size = 0;   if (file.is_open())   {     // get length of file     file.seekg(0,std::ios_base::end);     int length = *size = file.tellg();     file.seekg(0,std::ios_base::beg);      // allocate buffer in size of file     buffer = new char[length];      // read     file.read(buffer,length);     cout << file.gcount() << endl;    }    file.close(); } 

main:

void main() {   int size = 0;   char* buffer = NULL;   read_file("File.txt",&size,buffer);    for (int i = 0; i < size; i++)     cout << buffer[i];   cout << endl;  } 
like image 408
Elior Avatar asked Apr 10 '14 10:04

Elior


People also ask

What is the significance of Tellg () function?

The tellg() function is used with input streams, and returns the current “get” position of the pointer in the stream. It has no parameters and returns a value of the member type pos_type, which is an integer data type representing the current position of the get stream pointer.

How do I get the size of a file in C++?

To get a file's size in C++ first open the file and seek it to the end. tell() will tell us the current position of the stream, which will be the number of bytes in the file.

What is the use of Seekg and Tellg in C++?

seekg() is used to move the get pointer to a desired location with respect to a reference point. tellg() is used to know where the get pointer is in a file.


1 Answers

tellg does not report the size of the file, nor the offset from the beginning in bytes. It reports a token value which can later be used to seek to the same place, and nothing more. (It's not even guaranteed that you can convert the type to an integral type.)

At least according to the language specification: in practice, on Unix systems, the value returned will be the offset in bytes from the beginning of the file, and under Windows, it will be the offset from the beginning of the file for files opened in binary mode. For Windows (and most non-Unix systems), in text mode, there is no direct and immediate mapping between what tellg returns and the number of bytes you must read to get to that position. Under Windows, all you can really count on is that the value will be no less than the number of bytes you have to read (and in most real cases, won't be too much greater, although it can be up to two times more).

If it is important to know exactly how many bytes you can read, the only way of reliably doing so is by reading. You should be able to do this with something like:

#include <limits>  file.ignore( std::numeric_limits<std::streamsize>::max() ); std::streamsize length = file.gcount(); file.clear();   //  Since ignore will have set eof. file.seekg( 0, std::ios_base::beg ); 

Finally, two other remarks concerning your code:

First, the line:

*buffer = new char[length]; 

shouldn't compile: you have declared buffer to be a char*, so *buffer has type char, and is not a pointer. Given what you seem to be doing, you probably want to declare buffer as a char**. But a much better solution would be to declare it as a std::vector<char>& or a std::string&. (That way, you don't have to return the size as well, and you won't leak memory if there is an exception.)

Second, the loop condition at the end is wrong. If you really want to read one character at a time,

while ( file.get( buffer[i] ) ) {     ++ i; } 

should do the trick. A better solution would probably be to read blocks of data:

while ( file.read( buffer + i, N ) || file.gcount() != 0 ) {     i += file.gcount(); } 

or even:

file.read( buffer, size ); size = file.gcount(); 

EDIT: I just noticed a third error: if you fail to open the file, you don't tell the caller. At the very least, you should set the size to 0 (but some sort of more precise error handling is probably better).

like image 196
James Kanze Avatar answered Oct 02 '22 13:10

James Kanze