12

I am using fopen fseeko64 ftello64 fclose etc. to operating on a file.

How can I truncate a file? I know that there is no standard way to do this in C. All I want is some way that will work on any win32 platform. I'm using mingw gcc to compile.

Please note: I meant truncate the size of the file to a specified size, not make it 0 size. And using a trick like copy part to another file and delete/rename is not appropriate.

vvvvv
  • 25,404
  • 19
  • 49
  • 81

5 Answers5

17

SetEndOfFile()

Get a handle to the file with write access, set the file pointer, then call SetEndOfFile().

-Adam

Adam Davis
  • 91,931
  • 60
  • 264
  • 330
  • 1
    This unfortunately doesn't explain how to convert the FILE* value the OP has into a HANDLE suitable for passing to SetEndOfFile() – Malvineous Oct 15 '11 at 04:17
  • Besides what was already [mentioned in the comment](http://stackoverflow.com/questions/584639/truncate-file#comment9468490_584647) by [@Malvineous](http://stackoverflow.com/users/308237/malvineous)… I would like to note that you are pointing to a ***C++*** function, while OP asked about ***C*** and explicitly tagged the question with ***C*** accordingly. – e-sushi May 14 '14 at 07:08
5

If you want to truncate the file to zero size, you can fopen with the "w" flag:

FILE *fh = fopen("file.txt","w");
if (fh != NULL) fclose(fh);

For truncating to a specific size in standard C, you can do this with a transfer/rename solution, something like:

FILE *finp = fopen ("inp.txt", "rb");       // should check for NULLs
FILE *fout = fopen ("out.txt", "wb");

size_t sz = 100000;                         // 100,000 bytes
char *buff = malloc (sz);                   // should check for NULL

sz = fread (buff, 1, sz, fin);              // should check for errors
fwrite (buff, 1, sz, fout);

free (buff);

fclose (fin);
fclose (fout);

rename ("out.txt", "inp.txt);               // should check for error

Of course, if you have access to the Win32 headers and libraries (and I believe MinGW gives you this), you can use SetEndOfFile(), since it does it in place, rather than having to create a new file and then rename it.

That means using Windows handle-based file I/O rather than the C FILE*-based but, if you're limiting yourself to Windows anyway, that may not matter. If you want portability on the other hand, you'll need a solution based on standard C, such as the transfer/rename solution above.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Why are you using a pointer to a single character? You can use fgetc() and fputc() and just use a non-pointer (or not even a variable): for(int i = 0; i < 100000; i++) fputc(fgetc(fin), fout); – Chris Lutz Feb 25 '09 at 05:01
  • Which would result in 100,000 times as many function calls :-) – paxdiablo Feb 25 '09 at 05:11
  • Ah, there was some misreading. Sorry. (However, I don't think 100000 fgetc()s and fputc()s really take that long.) – Chris Lutz Feb 25 '09 at 05:59
  • 1
    Interesting, I was going to prove you wrong by writing sample programs but it appears you are right. Transfer of a 34M file actually takes longer (twice as long) with malloc and repeated fread(100k)/fwrite(100K) than with a repeated fgetc/fputc. So I'll wisely keep my mouth shut :-) – paxdiablo Feb 25 '09 at 10:09
4

For FILE based file operations, use _fileno() and _chsize_s() to change the size of a file.

int changesize(FILE *fp, __int64 size)
{
    int filedes = _fileno(fp);
    return _chsize_s(filedes, size);
}

A truncate version can be written by validating that the supplied size is less than the current file size, as _chsize_s() will truncate or extend a file's size - see http://msdn.microsoft.com/en-us/library/whx354w1(VS.80).aspx.

Martyn Davis
  • 625
  • 1
  • 10
  • 16
2

If you simply fopen() a file with the "w" argument, it will be truncated.

http://www.cplusplus.com/reference/clibrary/cstdio/fopen.html

Thomas
  • 174,939
  • 50
  • 355
  • 478
1

As mentioned already, you can use fopen() with the "w" flag like:

FILE *f = fopen("file.txt", "w");

Also, if you already have the file opened, you can use the function freopen(), again with the "w" flag:

FILE *f = fopen("file.txt", "r");  //initial fopen() call
...
f = freopen("file.txt", "w", f);   //reopens "file.txt" and truncates it

http://www.cplusplus.com/reference/clibrary/cstdio/freopen.html

EDIT: After seeing you've edited your OP, I won't repost what Pax and Adam Davis has already put. Also, I'll confirm what Pax said, that the MinGW does give you access to the Win32 headers.

DeadHead
  • 2,251
  • 16
  • 16