Pygar
Pygar

Reputation: 53

C, unix and overwriting a char with write(), open() and lseek()

I need to replace the a character in a text file with '?'. It's not working as expected.

The file has contents 'abc' (without quotes) and i've got to use the unix system calls: lseek(), open() and write(). I can't use the standard C file I/O functions.

The plan is to eventually exand this into a more generalised "find and replace" utility.

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(){

int file = open("data", O_RDWR); //open file with contents 'abc'
lseek(file,0,0); //positions at first char at beginnging of file. 
char buffer;
read(file,&buffer, sizeof(buffer));
printf("%c\n", buffer); // text file containing 'abc', it prints 'a'. 

if (buffer == 'a'){
    char copy = '?';
    write(file,&copy,1); //text file containing 'abc' puts '?' were 'b' is.
    }

close(file);
}

The file "data" contains abc, i want to replace a with ? and make it ?bc but i'm getting a?c

read() is reading the right char, but write() is writing to the next char. Why is this?

Been searching google for hours.

Thanks

Upvotes: 5

Views: 18657

Answers (3)

Veebot
Veebot

Reputation: 1

lseek is in the wrong place. Once 'a' has been found it writes '?' in the next available spot (which happens to overwrite 'b'). To fix, you need to change the current position using lseek BEFORE you write.

if (buffer == 'a'){
char copy = '?';
lseek(file,0,SEEK_SET); //positions at first char at beginnging of file.
write(file,&copy,1); //text file containing 'abc' puts '?' were 'b' is.
}

Upvotes: 0

mfsiega
mfsiega

Reputation: 2872

Your call to read() moves the file pointer forward one byte - i.e. from 0 to 1. Since you're using the same file descriptor ("int file = ...") for reading and writing, the position is the same for reading and writing.

To write over the byte that was just read, you need to lseek() back one byte after

(buffer == 'a') 

comes true.

Upvotes: 0

torek
torek

Reputation: 487893

The answer is actually embedded in your own code, in a way.

The lseek call you do right after open is not required because when you first open a file the current seek offset is zero.

After each successful read or write operation, the seek offset moves forward by the number of bytes read/written. (If you add O_APPEND to your open the seek offset also moves just before each write, to the current-end-of-file, but that's not relevant at this point.)

Since you successfully read one byte, your seek offset moves from 0 to 1. If you want to put it back to 0, you must do that manually.

(You should also check that each operation actually succeeds, of course, but I assume you left that out for brevity here.)

Upvotes: 5

Related Questions