【问题标题】:32 bit Windows and the 2GB file size limit (C with fseek and ftell)32 位 Windows 和 2GB 文件大小限制(带有 fseek 和 ftell 的 C)
【发布时间】:2010-10-23 09:56:02
【问题描述】:

我正在尝试将小型数据分析程序从 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 字节),这很奇怪。

奇怪的是,当我在对 _fseeki64 的调用中省略了 (__int64) 演员表时,我得到一个运行时错误(无效参数)。

有什么想法吗?

【问题讨论】:

  • 你用的是什么编译器?海合会?视觉(东西)?还有什么?
  • 我正在使用 MinGW(“不能”使用 VS,因为我正在编写的函数是 f2py Python 扩展模块的一部分)。如果 Win32 API 可以很容易地集成到这个函数中而不添加许多依赖项,那么它可能是一个选项(你可能会说我对 Windows 不太熟悉 :))
  • 我也发布了一个更具体的问题,如果得到回答,我也会在这里添加最终解决方案。

标签: c windows porting large-files c99


【解决方案1】:

很抱歉没有早点发布,但我已经有一段时间专注于其他项目了。 以下解决方案有效:

__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】:

    有两个函数称为 _fseeki64 和 _ftelli64,即使在 32 位 Windows 上也支持更长的文件偏移:

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

    【讨论】:

    • 我试过了,但它似乎没有返回正确的值(见帖子)
    • 你使用什么编译器?视觉工作室?什么版本?
    • 我使用最新版本的 MinGW(基本上是 GCC 4.5)。由于我正在编译的包是一个带有 f2py 的 Python 扩展,我不知道如何用 VisualStudio 编译它。
    • 我从未使用过 MinGW,所以恐怕我帮不上忙。但是您是否看过 ftellofseeko,它们是 Unix 类库中可用的 64 位版本的 ftellfseek ?
    • 我看过这些 (fseeko _ftello) 函数,但不确定它们是否也适用于 Windows(在我的 64 位 UNIX 机器上没有问题,因为我可以使用fseek 和 ftell 使用 64 位长,这确实是 Windows 特定的问题)。
    【解决方案3】:

    我的 BC 说:

    520093696 + 4294967296 => 4815060992

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • @Pim Schellart:我既不能确认也不能否认。我目前正在使用的两个 gcc 设置是 Linux/POSIX(在您的问题范围内)。对这些进行测试,我看到 fseek() 和 ftell() 的 LFS 行为。所以我无法在非 POSIX 环境中使用 gcc 进行测试。
      • fseeko 和 ftello 提供了最新的 MinGW gcc 4.8.2;你不需要 LibGw32C。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-11
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      相关资源
      最近更新 更多