I am calling these functions:
unsigned blah[5];
lseek(0, 100, SEEK_CUR);
read(0, blah, sizeof(blah));
and
FILE *fr;
fr = fopen(
SEEK_CUR starts from the current position. That is why your first seek works when you are at the beginning of the file. To always seek from the beginning you need to use SEEK_SET instead of SEEK_CUR.
0 SEEK_SET The beginning of the file
1 SEEK_CUR The current position
2 SEEK_END The end of the file
With the addition of an open(filename,O_RDONLY);
call to the first example, both worked fine for me. I suspect your problem is because of the call lseek(0, 100, SEEK_CUR);
, which is asking for a seek on standard input. You cannot always seek on standard in - if you have:
cat file | ./my_program
Then standard input is a fifo, and you can't seek. If I do this on my system, seek fails by returning -1
, with an error of "Illegal seek". This may be the problem you're having, and you might not notice since you don't check the return value of the seek call in your example.
Note that if you have:
./my_program < file
Then standard input is a file, and you may seek. On my system, seek returns 100
, and the output is correct.
Here is a program you can use to illustrate the return values:
int main(void){
int fd = 0;
char blah[5];
printf("Seek moved to this position: %d\n",lseek(fd, 100, SEEK_CUR));
perror("Seek said");
printf("Then read read %d bytes\n",read(fd, blah, sizeof(blah)));
printf("The bytes read were '%c%c%c%c%c'\n",blah[0],blah[1],blah[2],blah[3],blah[4]);
}
And here are two executions:
$ ./a.out < text
Seek moved to this position: 100
Seek said: Success
Then read read 5 bytes
The bytes read were '+++.-'
(Those are the correct bytes from position 100 in that file)
$ cat text | ./a.out
Seek moved to this position: -1
Seek said: Illegal seek
Then read read 5 bytes
The bytes read were '# def'
(Those bytes are the first 5 bytes of the file)
I also noticed that the standard input version was the one you said was working correctly. If you're having trouble with the FILE *
version, I suspect the fopen()
call is failing, so make sure you check the return value from fopen()
. Of course, you can always do this:
FILE *fr = stdin;
So that you're reading from standard in. However, as you can't always seek on standard in, I'd recommend always opening a file if you plan to seek.
Note that you can't seek on all devices that you can open files on (though you won't have a problem on most systems), so you should always check that the result of a seek()
to make sure it succeeded.
I'm not a 100% sure about the difference, but it seems to be related to pipe vs stdio/file. To illustrate this, I made these 2 different test programs:
exam.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
char blah[5] = {0,};
/* we're using stdin instead of pipeline :( */
lseek(0, 100, SEEK_CUR);
read(0, blah, sizeof(blah));
printf("%c%c%c%c%c\n", blah[0], blah[1], blah[2], blah[3], blah[4]);
return 0;
}
test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
void testA(const char *s)
{
int f = -1;
char blah[5] = {0,};
f = open(s, O_RDONLY);
if (-1 < f)
{
lseek(f, 100, SEEK_CUR);
read(f, blah, sizeof(blah));
}
printf("%c%c%c%c%c\n", blah[0], blah[1], blah[2], blah[3], blah[4]);
}
void testB(const char *s)
{
FILE *fp = NULL;
char blah[5] = {0,};
fp = fopen(s, "r");
if (fp)
{
fseek(fp, 100, SEEK_CUR);
fread(blah, 1, sizeof(blah), fp);
}
printf("%c%c%c%c%c\n", blah[0], blah[1], blah[2], blah[3], blah[4]);
}
int main(int argc, char **argv)
{
testA(argv[1]);
testB(argv[1]);
return 0;
}
Then I created some test data.
data.txt
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
When I executed cat ./data.txt | ./exam
, the output is
01234
When I executed ./test ./data.txt
, I got
bcdef
bcdef
Just FYI, the results remain unchanged even if we replace SEEK_CUR
with SEEK_SET
.
However, ./exam <./data.txt
results in
bcdef
which is legitimate.
I know this is not an acceptable answer without knowing why '0' brings up the data file's contents, but I hope it helps somehow.