tags:

views:

87

answers:

5

The footer should update with current time and hour when a new Item added to the file. Here is the sample file format,

ITEM1
ITEM2
06/07/2010 10:20:22 //footer line

The “item” has to append in the existing file, prior to the footer line, and the footer should be updated with new value. I am having to variables, “item” and “time” which hold the respective values as string.

After adding a new item (ITEM3) the file looks like,

ITEM1
ITEM2
ITEM3
07/07/2010 17:20:12 //changed footer

Help me to acheive this.

+3  A: 

Since the footer line is a static length...

Seek to the beginning of the footer line, write the new item over it followed by a newline, then write out the new footer.

(Note that this procedure is dangerous if you can't guarantee that you will always write at least enough total bytes to overwrite the existing footer, but it looks like you have exactly that assurance here.)

Nicholas Knight
good call on the static length (assuming it is, I assumed it wasn't), +1.
roe
could you please give a sample snippet for seek part?
arun
@arun; `char footer[] = "00/00/0000 00:00:00\n"; FILE *f = fopen ("myfile", "a+"); fseek(-(sizeof(footer)-1), SEEK_CUR)); fprintf(f, "My next item\n"); fwrite(footer, 1, sizeof(footer)-1, f); fclose(f);` the -1 on the sizeof is to remove the implicit null-termination in the string literal.
roe
Thanks a lot Nicholas :)
arun
I tried your code. But the value is appended only in last. That is after the footer. I tried debug the code as bellow: fp = fopen(FILEPATH,"a"); printf("Current pos : %d", ftell(fp) ); printf("FSEEK RETURNS : %d",fseek(fp,-43, SEEK_END)); printf("Current pos : %d", ftell(fp) );It prints :Current pos: 0FSEEK Returns:0Current pos: 142 // this value increased equal to the item for each run. i.e the item added at the last.Please guide me. Thank you.
arun
@arun; yes, sorry about that, see Matthews comment on my answer. It should be like this: `char footer[] = "00/00/0000 00:00:00\n"; FILE *f = fopen ("myfile", "r+"); fseek(-(sizeof(footer)-1), SEEK_END)); fprintf(f, "My next item\n"); fwrite(footer, 1, sizeof(footer)-1, f); fclose(f);`
roe
In POSIX, you can use [`pwrite()`](http://www.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) to write to an offset. However, I see nothing that indicates you can use a negative offset to write relative to the end of the file - which would be useful in this context.
Jonathan Leffler
+2  A: 

My solution would be, fopen with mode "r+" (reading and writing). fseek backwards from the end, a buffer length's worth and fill it (placing the cursor at the end again), search the buffer backwards for the last newline (if there is none, search even further back and repeat), once it has been found (or you hit the beginning of the file), search to that position in the file (your read placed it somewhere else), and write your new item, followed by a new line followed by a new footer. Close the file and truncate it to the right size.

HTH.

EDIT:
If the footer is always the same size, I'd definately go for Nicholas solution.

roe
Thank you. Since it is static length footer, I will try with Nicholas solution :)
arun
Could you please provide me a sample snippet for fseek? Thank you.
arun
I don't think `a+` is right. As [noted](http://stackoverflow.com/questions/3264495/appending-a-data-to-file-in-c/3264542#3264542) by bluesmoon, it should be `r+`. The [docs](http://www.opengroup.org/onlinepubs/009695399/functions/fopen.html) say any mode starting with 'a' causes all writes to be forced to the end regardless of seeks.
Matthew Flaschen
@Matthew; right.. my bad, it should be r+. Got that mixed up.
roe
A: 

A simple (but not very efficient) algorithm could look like this:

string content = "";
string line = "";

// Append every but the last line to content
while(!eof(file))
{
    content += line;
    line = readline(file);
}

content += getNewItem();
content += generateFooter();

save(content);
mxp
Thank you. The actual file is too large and I may face the buffer problem or less efficient as you said :)
arun
A: 

It is easy. You only have to truncate the last line.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NEWLINE "new line to append\n"

int main() {
  FILE *file;
  char *line = NULL;
  size_t previous_line_offset = 0, line_offset = 0;
  time_t time_signature;

  // open data file
  if((file = fopen("data.txt", "rw+")) == NULL) {
    puts("ERROR: Cannot open the file");
    return 1;
  }

  // find last line offset
  while(!feof(file)) {
    int n;
    previous_line_offset = line_offset;
    line_offset = ftell(file);
    getline(&line, &n, file); // NOTE getline is a GNU extension
  }

  // append new line
  fseek(file, previous_line_offset, SEEK_SET);
  fputs(NEWLINE, file);

  // apend signature
  time(&time_signature);
  fprintf(file, "%s", asctime(localtime(&time_signature)));

  // free resources
  fclose(file);
  if(line)
    free(line);

  // voila!
  return 0;
}
Victor Marzo
Thank you. Where can I get the getline()?
arun
getline is a GNU extension. It's only available in GNU libc library. On Visual Studio you could use std::getline (but it's c++).
Victor Marzo
Do you have any other solution which doesn't use any other extention?Thank you.
arun
You can use fgets http://en.wikipedia.org/wiki/Fgets
Victor Marzo
A: 

On a similar note; Whenever you modify a file, the file metadata changes to update the exact time of the last file write. You could always query that data with GetFileTime() on Windows.

sigint