¿Cuál es la diferencia entre este lseek, fseek, read, fread?

Estoy llamando a estas funciones:

unsigned blah[5]; lseek(0, 100, SEEK_CUR); read(0, blah, sizeof(blah)); 

y

 FILE *fr; fr = fopen(arg[1], "r"); unsigned blah[5]; fseek(fr, 100, SEEK_CUR); fread(blah, 1, sizeof(blah), fr); 

Y ejecuto el primer codigo mi ejecutando este comando:

 cat TEXTFILE | ./a.out 

Ejecuto el segundo código mi ejecutando este comando:

 ./a.out TEXTFILE 

Sin embargo, estoy obteniendo resultados diferentes. Mientras que el primero buscó correctamente, por lo que lee el texto correcto, el segundo no lo es. Quiero usar el segundo formato, entonces, ¿qué hice mal?

Con la adición de un open(filename,O_RDONLY); Llamado al primer ejemplo, ambos funcionaron bien para mí. Sospecho que su problema se debe a la llamada lseek(0, 100, SEEK_CUR); , que está pidiendo una búsqueda en la entrada estándar. No siempre se puede buscar en estándar – si tiene:

  cat file | ./my_program 

Entonces la entrada estándar es un fifo, y no puedes buscar. Si hago esto en mi sistema, la búsqueda falla al devolver -1 , con un error de “Búsqueda ilegal”. Este puede ser el problema que está teniendo y es posible que no se dé cuenta ya que no verifica el valor de retorno de la llamada de búsqueda en su ejemplo.

Tenga en cuenta que si tiene:

  ./my_program < file 

Entonces la entrada estándar es un archivo, y usted puede buscar. En mi sistema, la búsqueda devuelve 100 , y la salida es correcta.


Aquí hay un progtwig que puede usar para ilustrar los valores de retorno:

 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]); } 

Y aquí hay dos ejecuciones:

  $ ./a.out < text Seek moved to this position: 100 Seek said: Success Then read read 5 bytes The bytes read were '+++.-' 

(Esos son los bytes correctos de la posición 100 en ese archivo)

 $ cat text | ./a.out Seek moved to this position: -1 Seek said: Illegal seek Then read read 5 bytes The bytes read were '# def' 

(Esos bytes son los primeros 5 bytes del archivo)


También noté que la versión de entrada estándar era la que dijiste que estaba funcionando correctamente. Si tiene problemas con la versión FILE * , sospecho que la llamada fopen() está fallando, así que asegúrese de verificar el valor de retorno de fopen() . Por supuesto, siempre puedes hacer esto:

 FILE *fr = stdin; 

De modo que está leyendo desde el estándar. Sin embargo, como no siempre puede buscar el estándar, recomiendo siempre abrir un archivo si planea buscarlo.

Tenga en cuenta que no puede buscar en todos los dispositivos en los que puede abrir archivos (aunque no tendrá un problema en la mayoría de los sistemas), por lo que siempre debe verificar el resultado de la seek() para asegurarse de que tuvo éxito.

No estoy 100% seguro de la diferencia, pero parece estar relacionado con pipe vs stdio / file. Para ilustrar esto, hice estos 2 progtwigs de prueba diferentes:

examen.c

 #include  #include  #include  #include  #include  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; } 

prueba.c

 #include  #include  #include  #include  #include  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; } 

Entonces creé algunos datos de prueba.

data.txt

 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 

Cuando cat ./data.txt | ./exam cat ./data.txt | ./exam , la salida es

 01234 

Cuando ./test ./data.txt , obtuve

 bcdef bcdef 

Solo para su información, los resultados permanecen sin cambios incluso si reemplazamos SEEK_CUR con SEEK_SET .

Sin embargo, ./exam <./data.txt da como resultado

 bcdef 

lo cual es legitimo

Sé que esta no es una respuesta aceptable sin saber por qué '0' muestra el contenido del archivo de datos, pero espero que ayude de alguna manera.

SEEK_CUR comienza desde la posición actual. Es por eso que su primera búsqueda funciona cuando está al principio del archivo. Para buscar siempre desde el principio, debes usar SEEK_SET en lugar de SEEK_CUR.

 0 SEEK_SET The beginning of the file 1 SEEK_CUR The current position 2 SEEK_END The end of the file