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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4003405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:27:53  来源:igfitidea点击:

32 bit Windows and the 2GB file size limit (C with fseek and ftell)

cwindowsportinglarge-filesc99

提问by Pim Schellart

I am attempting to port a small data analysis program from a 64 bit UNIX to a 32 bit Windows XP system (don't ask :)). But now I am having problems with the 2GB file size limit (long not being 64 bit on this platform).

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

I have searched this website and others for possible sollutions but cannot find any that are directly translatable to my problem. The problem is in the use of fseek and ftell.

我已经在这个网站和其他网站上搜索了可能的解决方案,但找不到任何可以直接转化为我的问题的解决方案。问题出在 fseek 和 ftell 的使用上。

Does anyone know of a modification to the following two functions to make them work on 32 bit Windows XP for files larger than 2GB (actually order 100GB).

有谁知道对以下两个函数的修改,使它们能够在 32 位 Windows XP 上处理大于 2GB(实际订购 100GB)的文件。

It is vital that the return type of nsamples is a 64 bit integer (possibly int64_t).

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

and

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

I tried using _fseeki64 and _ftelli64 using the following to replace nsamples:

我尝试使用 _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;
}

for a file of 4815060992 bytesI get 260046848samples (e.g. _ftelli64gives 520093696bytes) which is strange.

对于4815060992 字节的文件,我得到260046848 个样本(例如_ftelli64给出520093696字节),这很奇怪。

Curiously when I leave out the (__int64)cast in the call to _fseeki64I get a runtime error (invalid argument).

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

Any ideas?

有任何想法吗?

采纳答案by Pim Schellart

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 _openinstead of fopento 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.

诀窍是使用_open而不是fopen打开文件。我仍然不明白为什么必须这样做,但至少现在有效。感谢大家的建议,最终为我指明了正确的方向。

回答by Codo

There are two functions called _fseeki64and _ftelli64that support longer file offsets even on 32 bit Windows:

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

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

__int64 _ftelli64(FILE *stream);

回答by Eric Towers

And for gcc, see SO question 1035657. Where the advice is compile with the flag -D_FILE_OFFSET_BITS=64 so that the hidden variable(s) (of type off_t) used by the f-move-around functions is(are) 64-bits.

对于 gcc,请参见 SO question 1035657。建议使用标志 -D_FILE_OFFSET_BITS=64 编译,以便 f-move-around 函数使用的隐藏变量(类型为 off_t)是 64 位。

For MinGW: "Large-file support (LFS) has been implemented by redefining the stat and seek functions and types to their 64-bits equivalents. For fseek and ftell, separate LFS versions, fseeko and ftello, based on fsetpos and fgetpos, are provided in LibGw32C." (reference). In recent versions of gcc, fseeko and ftello are built-in and a separate library is not needed.

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

回答by dascandy

My BC says:

我的 BC 说:

520093696 + 4294967296 => 4815060992

520093696 + 4294967296 => 4815060992

I'm guessing that your print routine is 32-bit. Your offset returned is most likely correct but being chopped off somewhere.

我猜你的打印程序是 32 位的。您返回的偏移量很可能是正确的,但在某处被砍掉了。