• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 219
  • Last Modified:

File Manipulation

How to delete the last line of a text file?
Efficient way please. Is it possible to do that without reading the entire file?
0
sonic2000
Asked:
sonic2000
  • 3
  • 3
1 Solution
 
Sys_ProgCommented:
If I assume I understood you properly,

If your file is fixed length line file, then it is

Using fseek ( fp, 0, END)  go to the end of file,
Then as you know the no of bytes in each line [being a fixed length line file],
again use fseek with a negative value of the size of the line.

HTH

Amit
0
 
Sys_ProgCommented:
sorry, END should be SEEK_END in the above call to fseek
0
 
Kent OlsenData Warehouse Architect / DBACommented:

Most of the time you won't know the length of the last line.  In that case you'll have to find it "the hard way" and then delete it by moving EOF with the truncate() function.

There are several ways to do this.  For short files, it's probably easiest to just read through the file, keeping track of the number of bytes read.  But this is not very efficient and will cause quite a delay on large files.  Here's (untested) code to do what you want.


#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFFERL 512  /* Disk I/O is usually in 512 word blocks, so reading 512 words at a time is pretty efficient  */

int FileHandle;

main (int argc, char **argv)
{
  int Buffer[BUFFERL];
  struct stat StatBuff;
  long FileLength;
  long DropCount;   /*  Not really used, but you might want to print it to stderr for debuggin  */
  long FilePosition;
  int   BlockLength;
  int idx;

  FileHandle = open (argv[1], O_RDWR);   /*  Sanity check needed that argv[1] actually exists and could be opened in this mode  */

  stat (argv[1], &StatBuff);  /*  If open() is successful, this should be, too  */
  FileLength = StatBuff.st_size;
  BlockLength = (StatBuff  & 0x7F);  /*  byte count in last 512 word block  */
  if (BlockLength == 0)
    BlockLength = BUFFREL
  DropCount = 0;

  while (FilePosition > 0)
  {
    FilePosition = FileLength - BlockLength;
    Read (FileHandle, Buffer, BlockLength);
    for (idx = BlockLength-1; idx >= 0; idx--)
      if (Buffer[idx] == '\n' || Buffer[idx] ==  '\r')  /*  found a carriage return or a line feed  */
      {
        truncate (FileHandle, FilePosition + idx);
        exit ();
      }
    DropCount += BlockLength;
    BlockLength = BUFFERL;
  }

  /*  no end of line found  */
}


Kent
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
sonic2000Author Commented:
SysProg, can you be more specific?
I tried this and it does not work

#include <stdio.h>
#include <string.h>

typedef struct CMD_INFO{
      char cmd[51];
      double startTime;
      double endTime;
      int pid;
} CMD_INFO;


void read_stat();
void delete_last_stat();

int main() {
      delete_last_stat();
      read_stat();
      
      return 1;
}


// read statistics from file
void read_stat() {
      CMD_INFO cmdInfo;
      FILE *fp;
      int i=0;

      fp = fopen(".stats.log", "r+");
      fseek(fp, 0, SEEK_SET);

      fread(&cmdInfo, sizeof(cmdInfo), 1, fp);
      while ( !feof(fp) ) {
            printf("Record %d\n", ++i);
            printf("cmd = %s\n", cmdInfo.cmd);
            printf("startTime = %f\n", cmdInfo.startTime);
            printf("endTime = %f\n", cmdInfo.endTime);
            printf("pid = %d\n\n", cmdInfo.pid);

            fread(&cmdInfo, sizeof(cmdInfo), 1, fp);
      }

      fclose(fp);
}

// Write statistics to file
void delete_last_stat() {
      CMD_INFO cmdInfo;
      FILE *fp;

      fp = fopen(".stats.log", "a+");
      fseek(fp, 0, SEEK_END);
      fseek(fp, (sizeof(cmdInfo))*-1, SEEK_CUR);

      fclose(fp);
}

.stats.log exists and has got contents. Content does not change after I use fseek. My understanding of fseek is to move the file pointer right?
0
 
Sys_ProgCommented:
I am sorry sonic2000

I mis-read your question. I thought u wanted to read the last line efficiently.

Sorry for that

Yes, fseek is only for moving the file pointer

But Yes, we can continue our apporach

Just use fteel to get the size of       File - Last line

and then use truncate

Here's the code for that

fseek ( fp, (sizeof(cmdInfo))*-1, SEEK_END ) ;
newsize = ftell ( fp ) ;
truncate ( fp, newsize ) ;

Just have a look at help for truncate
HTH

Amit


newsize =
0
 
sonic2000Author Commented:
thanks for replying.
at this time i have already solved my problem using google :)

I am using ftruncate();
0
 
sonic2000Author Commented:
but i know you are correct so you get the points.
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now