Click to See Complete Forum and Search --> : fseek / ftell, measuring text file length inaccurate?


MrDoomMaster
May 19th, 2006, 08:07 PM
Hi, I use fseek and ftell to get the number of characters in a text file. I'm not sure how efficient this is, but it's obviously not working.

I open my file using fopen with "rt":FILE* f = fopen(fullpath, "rt");

I get my file length like so: fseek(f, 0, SEEK_END);
int len = ftell(f);
fseek(f, 0, SEEK_SET);

In UltraEdit, the .txt file is reported having 2242 characters (with spaces). In code, ftell returns 2262. By checking the buffer and where the last character is, it's around 2190.

As you can see, I have three different numbers and I have no idea how to figure out how many characters are in the buffer. I cannot create a buffer for the text unless I know how many characters I need to allocate for.

Any help is greatly appreciated. Thank you.

kirants
May 19th, 2006, 08:21 PM
Refer MSDN.

The value returned by ftell might not reflect the physical byte offset for streams opened in text mode, because text mode causes carriage return–linefeed translation.

olivthill
May 19th, 2006, 08:29 PM
The problem is caused by the opening as a text file with "rt". Try opening it as a binary file with "rb", and the result should be better.

golanshahar
May 20th, 2006, 04:36 AM
Why you are not using the ::GetFileSize() (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfilesize.asp) api ?

Cheers

MrDoomMaster
May 20th, 2006, 03:51 PM
The reason why I don't open files in binary mode is because I actually WANT line endings to be converted to "\n".

Opening the file in text mode, is there any way I can get the correct file length?

golanshahar
May 20th, 2006, 04:50 PM
The reason why I don't open files in binary mode is because I actually WANT line endings to be converted to "\n".

Opening the file in text mode, is there any way I can get the correct file length?

Read my post, I offered you to use ::GetFileSize().

Here is a sample code:


HANDLE hFile =::CreateFile("c:\\myfile.txt",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if ( hFile == INVALID_HANDLE_VALUE)
return;
DWORD dwHightFileSize=0;
DWORD dwLowFileSize =::GetFileSize(hFile,&dwHightFileSize);

::CloseHandle(hFile);


Note this code is not complete if the dwHightFileSize !=0 you need to concat the low and high to get the real file size for more info about it refer to the MSDN.

Cheers

MrDoomMaster
May 20th, 2006, 05:11 PM
I cannot use those functions for portability issues.

golanshahar
May 20th, 2006, 05:30 PM
I cannot use those functions for portability issues.

So why you asking this question in win api forum?

/EDIT look also at: _filelength() (http://msdn2.microsoft.com/zh-tw/library/dfbc2kec.aspx)

Cheers

humptydumpty
May 20th, 2006, 11:47 PM
One Example Code is here .and if u r making File with yourself only.then you can keep track the no of text you had writen in the File and on that basis on can read that much basis you can read that much text from the File.

FILE *fp = NULL;
fp = fopen("C:\\Online_User.dat","rb");
if(fp==NULL)
return 0;
int dwSize;
fseek(fp,0,SEEK_END);
dwSize = ftell(fp); // get length of file
fseek(fp,0,SEEK_SET);
char *strReCeiveData = new char[dwSize+1]; // Dynamic array to copy file data to buffer
int it =fread(strReCeiveData,sizeof(char),dwSize,fp);
strReCeiveData[dwSize+1]='\0';
delete [] strReCeiveData ;
fclose(fp);


Thanx

charlass
May 21st, 2006, 09:03 AM
Use stat() if the code needs to be portable.

MrDoomMaster
May 22nd, 2006, 10:48 AM
So why you asking this question in win api forum?

It says C++ AND WinAPI. :rolleyes:



@Others

Thank you for all of the replies. I understand the difficulty of what I am trying to accomplish and I think the best resolution is to just load the data as binary, 1 byte at a time, ignoring any "\r" characters I may get. I'm not sure how inefficient this would be, since I can't see inside of fread(), but I guess we'll see.

Thanks again.

philkr
May 22nd, 2006, 11:10 AM
Why don't you open it in binary mode, calculate the size, close it and open it in text mode?
Whatever way you choose: Reading 1 byte at a time from disk IS inefficient. You should read larger blocks and then remove the \r from the buffer in memory.

golanshahar
May 22nd, 2006, 12:07 PM
It says C++ AND WinAPI. :rolleyes:




if ( I need C++ AND WinAPI )
{
goto C++ and WinAPI
}
else if ( I need only C++ With NO WinAPI)
{
goto C++ (Non Visual C++ Issues)
}


Now since you Don’t want WinAPI and you want portable c++ code, the “code” above should answer your question :D ;)

Cheers

golanshahar
May 22nd, 2006, 02:56 PM
@Others

Thank you for all of the replies. I understand the difficulty of what I am trying to accomplish and I think the best resolution is to just load the data as binary, 1 byte at a time, ignoring any "\r" characters I may get. I'm not sure how inefficient this would be, since I can't see inside of fread(), but I guess we'll see.

Thanks again.

Did you try _filelength() ?

Cheers