una txt texto separado por plano net linea leer especifica escribir como comas archivos archivo abrir c file io stream stdin

txt - leer una linea especifica de un archivo en c#



Leer de archivo o stdin (6)

¿Puede simplemente leer desde stdin a menos que el usuario proporcione un nombre de archivo?

Si no es así, trate el "nombre de archivo" especial - que significa "leer de la entrada estándar". El usuario tendría que iniciar el programa como cat file | myprogram - cat file | myprogram - si quiere canalizar datos a él, y myprogam file si quiere que se lea desde un archivo.

int main(int argc,char *argv[] ) { FILE *input; if(argc != 2) { usage(); return 1; } if(!strcmp(argv[1],"-")) { input = stdin; } else { input = fopen(argv[1],"rb"); //check for errors }

Si estás en * nix, puedes verificar si stdin es un fifo:

struct stat st_info; if(fstat(0,&st_info) != 0) //error } if(S_ISFIFO(st_info.st_mode)) { //stdin is a pipe }

Aunque eso no va a manejar el usuario haciendo myprogram <file

También puedes verificar si stdin es un terminal / consola

if(isatty(0)) { //stdin is a terminal }

Estoy escribiendo una utilidad que acepta un nombre de archivo, o lee desde stdin.

Me gustaría saber cuál es la forma más robusta y rápida de verificar si existe una entrada estándar (se están canalizando los datos al programa) y, si es así, leer esos datos. Si no existe, el procesamiento se realizará en el nombre del archivo. dado. He intentado usar la siguiente prueba para el tamaño de la stdin pero creo que ya que es una secuencia y no un archivo real, no está funcionando como sospechaba y siempre está imprimiendo -1 . Sé que siempre podría leer el carácter de entrada 1 a la vez mientras! = EOF, pero me gustaría una solución más genérica para poder terminar con un fd o un ARCHIVO * si existe una versión estándar para que el resto del programa funcione sin problemas . También me gustaría poder saber su tamaño, hasta que el programa anterior haya cerrado la secuencia.

long getSizeOfInput(FILE *input){ long retvalue = 0; fseek(input, 0L, SEEK_END); retvalue = ftell(input); fseek(input, 0L, SEEK_SET); return retvalue; } int main(int argc, char **argv) { printf("Size of stdin: %ld/n", getSizeOfInput(stdin)); exit(0); }

Terminal:

$ echo "hi!" | myprog Size of stdin: -1


Es posible que desee ver cómo se hace esto en la utilidad cat , por ejemplo.

Ver código here . Si no hay un nombre de archivo como argumento, o si es "-", entonces la stdin se usa para la entrada. stdin estará allí, incluso si no se le envían datos (pero entonces, su llamada de lectura puede esperar para siempre).


Estás pensando que está mal.

Lo que estás tratando de hacer:

Si existe una licencia estándar, úsela, o compruebe si el usuario proporcionó un nombre de archivo.

Lo que deberías estar haciendo en su lugar:

Si el usuario proporciona un nombre de archivo, utilice el nombre de archivo. Si no usa stdin.

No puede conocer la longitud total de un flujo entrante a menos que lo lea todo y lo mantenga en el búfer. Usted simplemente no puede buscar hacia atrás en las tuberías. Esta es una limitación de cómo funcionan las tuberías. Las tuberías no son adecuadas para todas las tareas y, a veces, se requieren archivos intermedios.


Primero, pida al programa que le diga qué está mal al verificar errno , que está configurado en falla, como durante fseek o ftell .

Otros (tonio y LatinSuD) explicaron el error con el manejo de stdin en lugar de verificar un nombre de archivo. A saber, primero verifique argc (cuenta de argumentos) para ver si hay algún parámetro de línea de comando especificado if (argc > 1) , tratando - como un caso especial que significa stdin .

Si no se especifican parámetros, entonces asuma que la entrada (va) provendrá de stdin , que es una secuencia no de archivo, y la función fseek falla en ella.

En el caso de una transmisión, en la que no puede usar funciones de biblioteca orientadas a archivos en disco (es decir, fseek y ftell ), simplemente debe contar el número de bytes leídos (incluidos los caracteres de nueva línea) hasta que reciba EOF (final de) expediente).

Para el uso con archivos grandes, podría acelerarlo utilizando fgets a una matriz de caracteres para una lectura más eficiente de los bytes en un archivo (texto). Para un archivo binario debe usar fopen(const char* filename, "rb") y usar fread lugar de fgetc/fgets .

También puede verificar el for feof(stdin) / ferror(stdin) al usar el método de conteo de bytes para detectar cualquier error al leer desde un flujo.

La siguiente muestra debe ser compatible con C99 y portátil.

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> long getSizeOfInput(FILE *input){ long retvalue = 0; int c; if (input != stdin) { if (-1 == fseek(input, 0L, SEEK_END)) { fprintf(stderr, "Error seek end: %s/n", strerror(errno)); exit(EXIT_FAILURE); } if (-1 == (retvalue = ftell(input))) { fprintf(stderr, "ftell failed: %s/n", strerror(errno)); exit(EXIT_FAILURE); } if (-1 == fseek(input, 0L, SEEK_SET)) { fprintf(stderr, "Error seek start: %s/n", strerror(errno)); exit(EXIT_FAILURE); } } else { /* for stdin, we need to read in the entire stream until EOF */ while (EOF != (c = fgetc(input))) { retvalue++; } } return retvalue; } int main(int argc, char **argv) { FILE *input; if (argc > 1) { if(!strcmp(argv[1],"-")) { input = stdin; } else { input = fopen(argv[1],"r"); if (NULL == input) { fprintf(stderr, "Unable to open ''%s'': %s/n", argv[1], strerror(errno)); exit(EXIT_FAILURE); } } } else { input = stdin; } printf("Size of file: %ld/n", getSizeOfInput(input)); return EXIT_SUCCESS; }


Sólo la prueba para el final del archivo con feof haría, creo.


Tenga en cuenta que lo que desea es saber si la entrada estándar está conectada a un terminal o no, no si existe. Siempre existe, pero cuando usa el shell para canalizar algo en él o leer un archivo, no está conectado a un terminal.

Puede verificar que un descriptor de archivo esté conectado a un terminal a través de las funciones termios.h:

#include <termios.h> #include <stdbool.h> bool stdin_is_a_pipe(void) { struct termios t; return (tcgetattr(STDIN_FILENO, &t) < 0); }

Esto intentará recuperar los atributos terminales de stdin. Si no está conectado a una tubería, está conectado a un tty y la llamada a la función tcgetattr se realizará correctamente. Para detectar una tubería, verificamos la falla de tcgetattr.