views:

99

answers:

2

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).

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.

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).

It is vital that the return type of nsamples is a 64 bit integer (possibly 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:

__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 bytes I get 260046848 samples (e.g. _ftelli64 gives 520093696 bytes) which is strange.

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

Any ideas?

+1  A: 

There are two functions called _fseeki64 and _ftelli64 that support longer file offsets even on 32 bit Windows:

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

__int64 _ftelli64(FILE *stream);
Codo
I tried this but it doesn't seem to return the right values (see post)
Pim Schellart
What compiler do you use? VisualStudio? And what version?
Codo
I use the latest version of MinGW (basically GCC 4.5). As the package I am compiling is a Python extension with f2py and I have no clue how to compile that with VisualStudio.
Pim Schellart
I've never used MinGW so I'm afraid I can't really help. But have you looked at _ftello_ and _fseeko_ which are 64 bit versions of _ftell_ and _fseek_ available in Unix like libraries?
Codo
I have looked as these (_fseeko_ _ftello) functions but am unsure if they also work on Windows (on my 64 bit UNIX machine there is no problem since I can just use fseek and ftell with the 64 bit long, it really is a Windows specific issue).
Pim Schellart
A: 
Eric Towers
I think that only works for GCC on a POSIX platform right?
Pim Schellart
@Pim Schellart: I can neither confirm nor deny that. My two currently working gcc setups are Linux/POSIX (within the context of your question). Testing on those, I see LFS behaviour from fseek() and ftell(). So I am unable to test with gcc in a non-POSIX environment.
Eric Towers