[comp.lang.c] How do you truncate a file?

cilibrar@athena.ecs.csus.edu (Rudi Cilibrasi) (05/05/91)

Suppose I have a 100-byte file called "myfile.dat", and I want to get
rid of the last 10 bytes.  The only way that I can figure out how to do
this is with something like the following:

main()
{
	char buf[100];
	FILE *fp;
	fp = fopen("myfile.dat", "r");
	fread(buf, 1, 100, fp);
	fclose(fp);
	fp = fopen("myfile.dat", "w");
	fwrite(buf, 1, 90, fp);
	fclose(fp);
}

This seems to be a rather roundabout way to accomplish a simple task.
Is there any way to accomplish the same thing without reading the entire
file into memory?  Thanks for any help.

henry@zoo.toronto.edu (Henry Spencer) (05/05/91)

In article <1991May5.024348.4203@csusac.csus.edu> cilibrar@athena.ecs.csus.edu (Rudi Cilibrasi) writes:
>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>rid of the last 10 bytes...

ANSI C provides no way to truncate a file without reading and rewriting it.
In fact, there is no portable way; some systems can't do it.

If you wanted a system-specific way to do it, you should ask the question
in a suitable newsgroup, like comp.os.msdos.programmer or comp.unix.questions.
-- 
And the bean-counter replied,           | Henry Spencer @ U of Toronto Zoology
"beans are more important".             |  henry@zoo.toronto.edu  utzoo!henry

fitz@mml0.meche.rpi.edu (Brian Fitzgerald) (05/06/91)

Rudi Cilibrasi writes:
>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>rid of the last 10 bytes.

#include <stdio.h>
main () {
int	i;
for (i=0; i < 90 ; i++) {
		(void) putchar(getchar());
	}
}

It has worked for me in the past.

Use the program with shell i/o redirection, as in

program < myfile.dat > truncated.dat

Brian

lwb@pensoft.uucp (Lance Bledsoe) (05/07/91)

In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
>Rudi Cilibrasi writes:
>>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>>rid of the last 10 bytes.
>
>#include <stdio.h>
>main () {
>int	i;
>for (i=0; i < 90 ; i++) {
>		(void) putchar(getchar());

Do you think you could have thought of a *slower* way to do this???



-- 
Lance Bledsoe                       Off:    (512) 343-1111                 
Pencom Software, Inc.               Fax     (512) 343-9650                 
8716 Loop 360 N. Suite 300          UUCP:   cs.utexas.edu!pensoft!lwb      
Austin, Texas  78759                UUNET:  uunet!uudell!pensoft!lwb       

jinx@milton.u.washington.edu (Flying On A Canvas Wing) (05/07/91)

In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
>Rudi Cilibrasi writes:
>>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>>rid of the last 10 bytes.
>
>#include <stdio.h>
>main () {
>int	i;
>for (i=0; i < 90 ; i++) {
>		(void) putchar(getchar());

You know, I may be wrong, but it seems that fread and fwrite would be
a little faster... 

-- 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!jinx@milton.u.washington.edu!!Disclaimer: OFS.*           !
!                            !!*Obligatory Fucking Smiley  !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

dfpedro@uswnvg.UUCP (Donn Pedro) (05/07/91)

In article <1991May6.194614.9641@pensoft.uucp>, lwb@pensoft.uucp (Lance Bledsoe) writes:
: In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
: >Rudi Cilibrasi writes:
: >>Suppose I have a 100-byte file called "myfile.dat", and I want to get
: >>rid of the last 10 bytes.
: >
: >#include <stdio.h>
: >main () {
: >int	i;
: >for (i=0; i < 90 ; i++) {
: >		(void) putchar(getchar());
: 
: Do you think you could have thought of a *slower* way to do this???

Could you then post the *faster* way?



	dfpedro@uswnvg.UUCP

r3jjs@VAX1.CC.UAKRON.EDU (Jeremy J Starcher) (05/08/91)

In article <1991May6.194614.9641@pensoft.uucp> lwb@pensoft.uucp (Lance Bledsoe) writes:
>In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
>>Rudi Cilibrasi writes:
>>>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>>>rid of the last 10 bytes.
>>
>>#include <stdio.h>
>>main () {
>>int	i;
>>for (i=0; i < 90 ; i++) {
>>		(void) putchar(getchar());
>
>Do you think you could have thought of a *slower* way to do this???
>

#include <stdio.h>
main () 
{
 int i;

  for (i = 0; i < 90; i++)
  {
    (void) putchar(getchar());
    sleep(60);            /* Make it even slower */
  }
}


-- 
--------------------------+---------------------------------------------------
Jeremy J Starcher         !  No programmer programs in LOGO after reaching
r3jjs@vax1.cc.uakron.edu  !  age 14...
r3jjs@akronvm.bitnet      !

fitz@mml0.meche.rpi.edu (Brian Fitzgerald) (05/08/91)

Lance Bledsoe writes:
>In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
>>Rudi Cilibrasi writes:
>>>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>>>rid of the last 10 bytes.
>>
>>#include <stdio.h>
>>main () {
>>int	i;
>>for (i=0; i < 90 ; i++) {
>>		(void) putchar(getchar());
>
>Do you think you could have thought of a *slower* way to do this???

Since the original poster's program uses fread and fwrite, it will run
much faster than mine does, especially if his fread and fwrite call a
decent assembler implementation of bcopy.

The speed point is well taken, but neither the buffered I/O functions
nor the character macros help Rudi, who would like to truncate his file
in place without reading it into memory or using a temporary file.
He's not running unix, and I think he's looking elsewhere for help
now.

Brian

campbell@dev8j.mdcbbs.com (Tim Campbell) (05/09/91)

In article <792@uswnvg.UUCP>, dfpedro@uswnvg.UUCP (Donn Pedro) writes:
> In article <1991May6.194614.9641@pensoft.uucp>, lwb@pensoft.uucp (Lance Bledsoe) writes:
> : In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
> : >Rudi Cilibrasi writes:
> : >>Suppose I have a 100-byte file called "myfile.dat", and I want to get
> : >>rid of the last 10 bytes.
> : >
> : >#include <stdio.h>
> : >main () {
> : >int	i;
> : >for (i=0; i < 90 ; i++) {
> : >		(void) putchar(getchar());
> : 
> : Do you think you could have thought of a *slower* way to do this???
> 
> Could you then post the *faster* way?
> 
> 
> 
> 	dfpedro@uswnvg.UUCP
-- 
I've seen some interesting and somewhat amusing responses to this one so
far.

IF you have DOS and want this to run real fast on any file of any size and
want it to truncate the file in place (not making a copy), then you could
always fseek to the 10th byte from the end of the file and overwrite and EOF
mark, then edit the directory entry in DOS to indicate that the file is now
10 bytes smaller.  Of course you'd need to know the layout of a directory
entry and although the code would run faster compared to this example 
(especially on big files), it would certainly require more time to write
the code.  I'd only write it if I needed to do this often.  Of course if
I didn't need to do this often then I'd probably just use a text editor.

I just don't know unix well enough to know a clever way to handle this 
situation without actually copying the file.

	-Tim

  ---------------------------------------------------------------------------
	  In real life:  Tim Campbell - Electronic Data Systems Corp.
     Usenet:  campbell@dev8.mdcbbs.com   @ McDonnell Douglas M&E - Cypress, CA
       also:  tcampbel@einstein.eds.com  @ EDS - Troy, MI
 CompuServe:  71631,654	 	 (alias  71631.654@compuserve.com)
 P.S.  If anyone asks, just remember, you never saw any of this.

djd@sirdan.sybase.com (dan debrunner) (05/10/91)

In article <1991May6.194614.9641@pensoft.uucp> lwb@pensoft.uucp (Lance Bledsoe) writes:
>In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
>>Rudi Cilibrasi writes:
 >>>Suppose I have a 100-byte file called "myfile.dat", and I want to get
 >>>rid of the last 10 bytes.
 >>
 >>#include <stdio.h>
 >>main () {
 >>int	i;
 >>for (i=0; i < 90 ; i++) {
 >>		(void) putchar(getchar());
 >
 >Do you think you could have thought of a *slower* way to do this???

Actually a correct way would have been even better. Remember putchar()
is a macro on many platforms which evaluates its argument twice.

Dan.

gwyn@smoke.brl.mil (Doug Gwyn) (05/12/91)

In article <12653@sybase.sybase.com> djd@sirdan.sybase.com (dan debrunner) writes:
>Actually a correct way would have been even better. Remember putchar()
>is a macro on many platforms which evaluates its argument twice.

It had better not be -- that is not only not conformant to the C standard,
it would break LOTS of code, such as the putchar(getchar()) loop.

jjr@rushpc (John J. Rushford Jr) (05/12/91)

In article <1991May9.130725.1@dev8j.mdcbbs.com> campbell@dev8j.mdcbbs.com (Tim Campbell) writes:
>In article <792@uswnvg.UUCP>, dfpedro@uswnvg.UUCP (Donn Pedro) writes:
>> In article <1991May6.194614.9641@pensoft.uucp>, lwb@pensoft.uucp (Lance Bledsoe) writes:
>> : In article <f25g_zd@rpi.edu> fitz@mml0.meche.rpi.edu (Brian Fitzgerald) writes:
>> : >Rudi Cilibrasi writes:
>> : >>Suppose I have a 100-byte file called "myfile.dat", and I want to get
>> : >>rid of the last 10 bytes.
>> : >
>> 	dfpedro@uswnvg.UUCP
>-- 
>I've seen some interesting and somewhat amusing responses to this one so
>far.
>
>IF you have DOS and want this to run real fast on any file of any size and
>want it to truncate the file in place (not making a copy), then you could
>always fseek to the 10th byte from the end of the file and overwrite and EOF
>mark, then edit the directory entry in DOS to indicate that the file is now
>10 bytes smaller.  Of course you'd need to know the layout of a directory
>entry and although the code would run faster compared to this example 
>(especially on big files), it would certainly require more time to write
>the code.  I'd only write it if I needed to do this often.  Of course if
>I didn't need to do this often then I'd probably just use a text editor.
>
>I just don't know unix well enough to know a clever way to handle this 
>situation without actually copying the file.
>

In Unix the above method would wreak havoc with the filesystem if you
could use it.  You would have to update the freelist and inode entry
in the superblock or run fsck -y to fix the filesystem.  This would
prove to be difficult unless you're 'root'.


-- 

John
----
Westminster Colorado	|

kremer@tulip.cs.odu.edu (Lloyd Kremer) (05/13/91)

In article <1991May9.130725.1@dev8j.mdcbbs.com> campbell@dev8j.mdcbbs.com (Tim Campbell) writes:
>
>IF you have DOS and want this to run real fast on any file of any size and
>want it to truncate the file in place (not making a copy), then you could
>always fseek to the 10th byte from the end of the file and overwrite and EOF
>mark, then edit the directory entry in DOS to indicate that the file is now
>10 bytes smaller.


If you're running DOS, there is an "official" method to truncate files
in-place.  You open a file handle to the existing file, seek to the intended
point of truncation, and perform a zero-length write.

Caveat: Most C Compilers don't implement this in their write() function.
You must use the real *DOS* function call, "write to open file handle," or
whatever it's called.  DOS C compilers provide a function like intdos() or
bdos() to access DOS functions directly, calling them with the right register
settings.  I think it's DOS function 3D or 3E or around there (I don't have my
DOS Technical Reference here).

Since this is the legitimate method in DOS, it takes care of the directory
entry and FAT automatically.

P.S.  This whole issue is not a C Language question; it's entirely an
operating system concern.
-- 

					Lloyd Kremer
					Hilton Systems, Inc.
					Hampton, Virginia 23666

jap@convex.cl.msu.edu (Joe Porkka) (05/13/91)

jjr@rushpc (John J. Rushford Jr) writes:

>In article <1991May9.130725.1@dev8j.mdcbbs.com> campbell@dev8j.mdcbbs.com (Tim Campbell) writes:
>>In article <792@uswnvg.UUCP>, dfpedro@uswnvg.UUCP (Donn Pedro) writes:
>>> In article <1991May6.194614.9641@pensoft.uucp>, lwb@pensoft.uucp (Lance Bledsoe) writes:
>>IF you have DOS and want this to run real fast on any file of any size and
>>want it to truncate the file in place (not making a copy), then you could
>>
>>I just don't know unix well enough to know a clever way to handle this 
>>situation without actually copying the file.
>>

>In Unix the above method would wreak havoc with the filesystem if you
>could use it.  You would have to update the freelist and inode entry
>in the superblock or run fsck -y to fix the filesystem.  This would
>prove to be difficult unless you're 'root'.

It would not be a problem on UNIX, or any REAL os ( !msdos). Simply
call "ftruncate()" and let the filesystem do its business.