32位Windows和2GB文件大小限制(C与fseek和ftell)

时间:2010-10-23 09:56:03

标签: c windows porting large-files c99

我正在尝试将一个小型数据分析程序从64位UNIX移植到32位Windows XP系统(不要问:))。 但是现在我遇到了2GB文件大小限制的问题(在这个平台上长时间不是64位)。

我搜索了这个网站和其他人可能的搜索,但找不到任何可以直接翻译我的问题。 问题在于使用fseek和ftell。

有没有人知道对以下两个函数的修改,使它们可以在32位Windows XP上运行大于2GB的文件(实际上是100GB)。

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 字节),这很奇怪。< / p>

奇怪的是,当我在(__int64)的调用中省略_fseeki64强制转换时,我收到运行时错误(无效参数)。

有什么想法吗?

4 个答案:

答案 0 :(得分:3)

有两个名为_ fseeki64 和_ ftelli64 的函数,即使在32位Windows上也支持更长的文件偏移量:

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

__int64 _ftelli64(FILE *stream);

答案 1 :(得分:3)

抱歉没有尽快发布,但我一直专注于其他项目。 以下解决方案有效:

__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来打开文件。 我仍然不明白为什么要这样做,但至少现在这样做了。 感谢大家的建议,最终指引我朝着正确的方向前进。

答案 2 :(得分:1)

对于gcc,请参阅问题1035657。使用标志-D_FILE_OFFSET_BITS = 64编译通知时,f-move-around函数使用的隐藏变量(类型为off_t)为64位。

对于MinGW:“大文件支持(LFS)已经通过将stat和seek函数和类型重新定义为64位等价来实现。对于fseek和ftell,基于fsetpos和fsetpos分离LFS版本,fseeko和ftello fgetpos,在LibGw32C中提供。“ (reference)。在最新版本的gcc中,fseeko和ftello是内置的,不需要单独的库。

答案 3 :(得分:1)

我的BC说:

  

520093696 + 4294967296 =&gt; 4815060992

我猜你的打印例程是32位的。您返回的偏移很可能是正确的,但在某处被切断。