tags:

views:

112

answers:

3

I have a binary file in CSV format that contains multiple records. Each record is entered in as user_name, last_name, first_name, num_wins, num_losses, num_ties. I am creating a method to update a certain players record of wins,losses and ties. The user inputs the username to change followed by the changes to the wins, losses and ties. For example smithj 4 5 1. This will find the smithj record and add 4 to the wins etc.

How do I use lseek or fseek to accomplish this? Or is there another way to do this?

+1  A: 

Assuming the file is a text file, then you will have to pad the lines to a constant width. Then use lseek(), read(), and write() to modify the lines. Having a constant length for each line is crucial: it allows you to compute the starting position of each line.

Steve Emmerson
+1  A: 

It's fairly easy to do if each record is the same number of bytes. You would check the first record to see if it's a match, and if not then do fseek(f, record_size, SEEK_CUR); and check the next record.

If each record is going to be a different number of bytes, all I can think of is that you put the number of bytes the record is before the actual record. And then read that in, and then fseek() that many bytes to get to the next record size. I've seen some binary file formats do this which makes things fairly easy.

jonescb
You have to read as well as seek - or, more usually, you read until you find, then rewind (with fseek()) to the start of the record so you can overwrite it. If you only read part of the record, you might need to do seeks between the reads. However, the disk drive will probably be read in chunks that are 4096 bytes long (some power of 2 between 512 bytes and about 16 KiB) and unless your record is extraordinarily long, you will merely be shuffling data around in your program by reading less than the full record; the actual disk traffic won't be affected by partial record reads.
Jonathan Leffler
Would it be possible for someone to write up an example of how to do this?
Jogan
+1  A: 

Response to request for write-up of example - assuming fixed size records:

enum { RECSIZE = 256 };

char buffer[RECSIZE];
FILE *fp = ...;   // File to read from and write to

int recnum = 37;  // Counting from record 0
long offset = recnum * RECSIZE;

if (fseek(fp, offset, SEEK_SET) != 0)
    ...error...
if (fread(buffer, sizeof(buffer), 1, fp) != 1)
    ...error...
...modify buffer...
if (fseek(fp, offset, SEEK_SET) != 0)
    ...error...
if (fwrite(buffer, sizeof(buffer), 1, fp) != 1)
    ...error...

Repeat the code from the declaration of recnum to the end once for each record that must be modified (think loop).

With variable size records that change size as you edit them, you have to work a lot harder - so much so that it is probably simpler to copy the old file into memory one record at a time, modifying the record appropriately, and then writing the modified record to a new file.

Jonathan Leffler