2

I have reduced the problem to the following basic function which should simply print the number of bytes in the file.

When I execute it for a file of 83886080 bytes (80 MB) it prints the correct number. However for a file of 4815060992 bytes (4.48 GB) it prints 520093696 which is way to low.

It seems to have something to do with the SEEK_END option because if I set the pointer to 4815060992 bytes manually (e.g. _fseeki64(fp, (__int64)4815060992, SEEK_SET) _ftelli64 does return the correct position. So a workaround would be to get the proper file size without using SEEK_END, how is this done?

The code is compiled on a 32 bit Windows system (hence __int64, _iseeki64 and _ftelli64) with MinGW.

In short: what am I doing wrong here?

void printbytes(char* filename)
{
  FILE *fp;
  __int64 n;
  int result;

  /* Open file */
  fp = fopen(filename, "rb");
  if (fp == NULL)
  {
    perror("Error: could not open file!\n");
    return -1;
  }

  /* Find end of file */
  result = _fseeki64(fp, (__int64)0, SEEK_END);
  if (result)
  {
    perror("Error: fseek failed!\n");
    return result;
  }

  /* Get number of bytes */
  n = _ftelli64(fp);

  printf("%I64d\n", n);

  /* Close file */
  fclose(fp);
}
Pim Schellart
  • 715
  • 1
  • 6
  • 18
  • 1
    instead of just printing that you had an error, print the error that you have. – KevinDTimm Oct 27 '10 at 14:34
  • 1
    `2^32 + 520093696 = 4815060992` But it should work, seeing your n is of type `__int64` --- whatever that is :) – pmg Oct 27 '10 at 14:38
  • Could be a bug in printf() too. – Hans Passant Oct 27 '10 at 15:21
  • @pmg, i was just too lazy to grab a calculator to figure that out -- but it was my first guess ;) – KevinDTimm Oct 27 '10 at 15:56
  • Hmm, it does not seem to be a printing error because if I add 2^32 (@pmg nicely spotted) to the number before printing it does print the correct value. For some reason _fseeki seems to position the file pointer in the wrong spot. – Pim Schellart Oct 28 '10 at 10:07

2 Answers2

2

sorry for not posting sooner but I have been preoccupied with other projects for a while. The following solution works:

__int64 nsamples(char* filename)
{
  int fh;
  __int64 n;

  /* Open file */
  fh = _open( filename, _O_BINARY );

  /* Find end of file */
  n = _lseeki64(fh, 0, SEEK_END);

  /* Close file */
  _close(fh);

 return n / sizeof(short);
}

The trick was using _open instead of fopen to open the file. I still don't understand exactly why this has to be done, but at least this works now. Thanks to everyone for your suggestions which eventually pointed me in the right direction. (this is a copy of the answer to related question number 4003405).

Pim Schellart
  • 715
  • 1
  • 6
  • 18
1

In Windows, you should be able to "go native" and just use GetFileSizeEx().

I would also advise you to read the generated code to see if it maybe is some 64-bit confusion that prevents your stdio-based code from working.

unwind
  • 391,730
  • 64
  • 469
  • 606