В Windows _fseeki64 неправильно ищет SEEK_END для больших файлов

Я сократил проблему до следующей базовой функции, которая должна просто печатать количество байтов в файле.

Когда я выполняю его для файла размером 83886080 байт (80 МБ), он печатает правильный номер. Однако для файла размером 4815060992 байта (4,48 ГБ) он печатает 520093696, что слишком мало.

Кажется, это как-то связано с параметром SEEK_END, потому что, если я вручную установлю указатель на 4815060992 байта (например, _fseeki64(fp, (__int64)4815060992, SEEK_SET) _ftelli64 действительно вернет правильную позицию. Таким образом, обходной путь будет заключаться в том, чтобы получить правильный размер файла без с помощью SEEK_END, как это делается?

Код скомпилирован в 32-битной системе Windows (отсюда __int64, _iseeki64 и _ftelli64) с MinGW.

Короче: что я здесь делаю не так?

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);
}

person Pim Schellart    schedule 27.10.2010    source источник
comment
вместо того, чтобы просто печатать, что у вас была ошибка, напечатайте ту ошибку, которая у вас есть.   -  person KevinDTimm    schedule 27.10.2010
comment
2^32 + 520093696 = 4815060992 Но это должно работать, видя, что ваш n имеет тип __int64 --- что бы это ни было :)   -  person pmg    schedule 27.10.2010
comment
Также может быть ошибка в printf().   -  person Hans Passant    schedule 27.10.2010
comment
@pmg, мне просто было лень брать калькулятор, чтобы понять это, но это была моя первая догадка;)   -  person KevinDTimm    schedule 27.10.2010
comment
Хм, похоже, это не ошибка печати, потому что, если я добавлю 2 ^ 32 (@pmg красиво замечено) к числу перед печатью, оно напечатает правильное значение. По какой-то причине _fseeki позиционирует указатель файла не в том месте.   -  person Pim Schellart    schedule 28.10.2010


Ответы (2)


В Windows вы должны иметь возможность «перейти к родному» и просто использовать GetFileSizeEx().

Я бы также посоветовал вам прочитать сгенерированный код, чтобы увидеть, не является ли это какой-то 64-битной путаницей, которая мешает работе вашего кода на основе stdio.

person unwind    schedule 27.10.2010

извините, что не опубликовала раньше, но я какое-то время был занят другими проектами. Работает следующее решение:

__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);
}

Хитрость заключалась в использовании _open вместо fopen для открытия файла. Я до сих пор не понимаю, зачем это нужно делать, но, по крайней мере, теперь это работает. Спасибо всем за ваши предложения, которые в конечном итоге указали мне в правильном направлении. (это копия ответа на соответствующий вопрос № 4003405).

person Pim Schellart    schedule 15.02.2011