32-битная Windows и ограничение размера файла 2 ГБ (C с fseek и ftell) - PullRequest
5 голосов
/ 23 октября 2010

Я пытаюсь перенести небольшую программу анализа данных с 64-битной UNIX на 32-битную систему Windows XP (не спрашивайте :)).Но теперь у меня проблемы с ограничением размера файла 2 ГБ (долго не являющимся 64-битным на этой платформе).

Я искал этот сайт и другие, чтобы найти возможные решения, но не могу найти ни одного, который был бы напрямую переведен в мою проблему.,Проблема заключается в использовании fseek и ftell.

Кто-нибудь знает о модификации следующих двух функций, чтобы они работали в 32-битной Windows XP для файлов размером более 2 ГБ (фактически порядка 100 ГБ).

Очень важно, чтобы возвращаемый тип nsamples представлял собой 64-разрядное целое число (возможно, int64_t).

long nsamples(char* filename)
{
  FILE *fp;
  long n;

  /* Open file */
  fp = fopen(filename, "rb");

  /* Find end of file */
  fseek(fp, 0L, SEEK_END);

  /* Get number of samples */
  n = ftell(fp) / sizeof(short);

  /* Close file */
  fclose(fp);

  /* Return number of samples in file */
  return n;
}

и

void readdata(char* filename, short* data, long start, int n)
{
  FILE *fp;

  /* Open file */
  fp = fopen(filename, "rb");

  /* Skip to correct position */
  fseek(fp, start * sizeof(short), SEEK_SET);

  /* Read data */
  fread(data, sizeof(short), n, fp);

  /* Close file */
  fclose(fp);
}

Я пытался использовать _fseeki64 и _ftelli64, используядля замены nsamples:

__int64 nsamples(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 samples */
  n = _ftelli64(fp) / sizeof(short);

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

  /* Close file */
  fclose(fp);

  /* Return number of samples in file */
  return n;
}

для файла размером 4815060992 Я получаю 260046848 выборок (например, _ftelli64 дает 520093696 байтов), что странно.

Любопытно, что когда я опускаю приведение (__int64) в вызове _fseeki64, я получаю ошибку во время выполнения (неверный аргумент).

Есть идеи?

Ответы [ 4 ]

3 голосов
/ 15 февраля 2011

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

__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, чтобы открыть файл. Я до сих пор точно не понимаю, почему это нужно делать, но, по крайней мере, сейчас это работает. Спасибо всем за ваши предложения, которые в конечном итоге указали мне в правильном направлении.

3 голосов
/ 23 октября 2010

Существуют две функции: _ fseeki64 и _ ftelli64 , которые поддерживают более длинные смещения файлов даже в 32-битной Windows:

int _fseeki64(FILE *stream, __int64 offset, int origin);

__int64 _ftelli64(FILE *stream);
1 голос
/ 16 декабря 2010

Мой БК говорит:

520093696 + 4294967296 => 4815060992

Я предполагаю, что ваша процедура печати 32-битная. Ваше возвращенное смещение, скорее всего, правильное, но где-то отрублено.

1 голос
/ 23 октября 2010

А для gcc см. ТАК вопрос 1035657 .Где рекомендация компилируется с флагом -D_FILE_OFFSET_BITS = 64, так что скрытая переменная (ии) (типа off_t), используемая функциями f-move -round, (являются) 64-битными.: «Поддержка больших файлов (LFS) была реализована путем переопределения функций stat и seek и типов к их 64-битным эквивалентам. Для fseek и ftell отдельные версии LFS, fseeko и ftello, основанные на fsetpos и fgetpos, представлены LibGw32C «.(* 1 007 * ссылка ).В последних версиях gcc встроены fseeko и ftello, и отдельная библиотека не нужна.

...