que - Pasando por un archivo de texto línea por línea en C
programa en c que lea un archivo txt (4)
Además de las otras respuestas, en una biblioteca de C reciente (compatible con Posix 2008), puede usar getline . Ver esta respuesta (a una pregunta relacionada).
He estado trabajando en un pequeño ejercicio para mi clase CIS y estoy muy confundido por los métodos que C usa para leer un archivo. Todo lo que realmente necesito hacer es leer un archivo línea por línea y usar la información recopilada de cada línea para hacer algunas manipulaciones. Intenté usar el método getline y otros sin suerte. Mi código es actualmente como sigue:
int main(char *argc, char* argv[]){
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file)){
sscanf(line, filename, "%s");
printf("%s/n", line);
}
return 1;
}
Ahora mismo estoy teniendo una falla de seg con el método sscanf y no estoy seguro de por qué. Soy un total de C noob y me pregunto si había algo del panorama general que me faltaba. Gracias
Digamos que está tratando con algún otro delimitador, como una pestaña /t
, en lugar de una /n
nueva línea.
Un enfoque más general de los delimitadores es el uso de getc()
, que capta un personaje a la vez.
Tenga en cuenta que getc()
devuelve un int
, para que podamos probar la igualdad con EOF
.
En segundo lugar, definimos una line[BUFFER_MAX_LENGTH]
matriz line[BUFFER_MAX_LENGTH]
de tipo char
, para almacenar hasta BUFFER_MAX_LENGTH-1
caracteres en la pila (tenemos que guardar ese último carácter para un carácter terminador /0
).
El uso de una matriz evita la necesidad de usar malloc
y free
para crear un puntero de carácter de la longitud correcta en el montón.
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments/n"
"usage: %s textfile/n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s/n", argv[1]);
return EXIT_FAILURE;
}
/* get a character from the file pointer */
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH./n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = ''/0'';
fprintf(stdout, "%s/n", line);
break;
}
else if (tempChar == ''/n'') {
line[tempCharIdx] = ''/0'';
tempCharIdx = 0U;
fprintf(stdout, "%s/n", line);
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
Si debe usar un char *
, entonces puede seguir usando este código, pero strdup()
la line[]
array, una vez que se llena con el valor de entrada de una línea. Debe free
esta cadena duplicada una vez que haya terminado con ella, o obtendrá una pérdida de memoria:
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments/n"
"usage: %s textfile/n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s/n", argv[1]);
return EXIT_FAILURE;
}
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH./n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = ''/0'';
dynamicLine = strdup(line);
fprintf(stdout, "%s/n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
}
else if (tempChar == ''/n'') {
line[tempCharIdx] = ''/0'';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s/n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
Para leer una línea de un archivo, debe usar la función fgets
: Lee una cadena desde el archivo especificado hasta un carácter de nueva línea o EOF
.
El uso de sscanf
en su código no funcionaría en absoluto, ya que usa el filename
como su cadena de formato para leer desde una line
hasta una cadena constante literal %s
.
El motivo de SEGV es que escribe en la memoria no asignada apuntada por line
.
Tantos problemas en tan pocas líneas. Probablemente me olvide de algunos:
- argv [0] es el nombre del programa, no el primer argumento;
- Si quieres leer en una variable, tienes que asignar su memoria.
- uno nunca realiza un bucle en feof, uno hace un bucle en una función IO hasta que falla, feof sirve para determinar el motivo del fallo,
- sscanf está ahí para analizar una línea, si desea analizar un archivo, use fscanf,
- "% s" se detendrá en el primer espacio como formato para la familia? scanf
- Para leer una línea, la función estándar es fgets,
- devolviendo 1 del fallo de medios principales
Asi que
#include <stdio.h>
int main(int argc, char* argv[])
{
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file)) {
/* note that fgets don''t strip the terminating /n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
}
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
}