hierro
Escribí esta función para leer una línea de un archivo:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
La función lee el archivo correctamente y, al usar printf, veo que la cadena constLine también se leyó correctamente.
Sin embargo, si uso la función, por ejemplo, así:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf genera un galimatías. ¿Por qué?
mbaitoff
Si su tarea no es inventar la función de lectura línea por línea, sino simplemente leer el archivo línea por línea, puede usar un fragmento de código típico que involucre el getline()
función (ver la página del manual aquí):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
-
Más precisamente, este
getline
es específico de GNU libc, es decir, de Linux. Sin embargo, si la intención es tener una función de lectura de líneas (en lugar de aprender C), hay varias funciones de lectura de líneas de dominio público disponibles en la web.– Gilles ‘SO- deja de ser malvado’
17 de agosto de 2010 a las 11:55
-
¿Por qué debería hacer eso? Lea el manual, el búfer se reasigna en cada llamada, luego debe liberarse al final.
– mbaitoff
30 de noviembre de 2012 a las 12:43
-
Él
if(line)
el cheque es superfluo. Vocaciónfree(NULL)
es esencialmente un no-op.– aroth
28 de enero de 2014 a las 7:25
-
@PhilipAdler Si realmente quieres pelear
free(NULL)
siendo no especificado (aunque estoy bastante seguro de que en ninguna parte está escrito así), entonces debes saber que inclusols
llamadasfree(NULL)
. Después de verificar, la página del manual dice quefree(ptr); free(ptr);
es indefinido, y esofree(NULL)
no hace nada. @mbaitoff Entonces, ¿por qué te molestas en liberarline
entonces ? Aún así, este sitio web tiene que ver con enseñar o ayudar con el mejor solución posible, y liberar cada memoria asignada que ya no se usa es en realidad una buena práctica.– Jerska
13 de junio de 2014 a las 18:59
-
Para aquellos que dijeron que este getline es específico de GNU libc, “Tanto getline() como getdelim() eran originalmente extensiones de GNU. Se estandarizaron en POSIX.1-2008”.
– willkill07
21/04/2015 a las 21:01
Robar
FILE* filePointer;
int bufferLength = 255;
char buffer[bufferLength]; /* not ISO 90 compatible */
filePointer = fopen("file.txt", "r");
while(fgets(buffer, bufferLength, filePointer)) {
printf("%s\n", buffer);
}
fclose(filePointer);
-
Para mí, esto da como resultado sobrescribir cada línea con la siguiente. Vea esta pregunta basada en la respuesta anterior.
– Cezar Cobuz
8 de enero de 2019 a las 3:09
-
porque el elenco
(FILE*) fp
? no esfp
ya es unFILE *
y tambiénfopen()
devuelve unFILE *
?– Contador م
04/04/2019 a las 23:25
-
Si está de acuerdo con que las líneas se limiten a una cierta longitud, esta es la mejor respuesta. De lo contrario usando
getline
es una buena alternativa. estoy de acuerdo conFILE *
el elenco es innecesario.– theicfire
17 de octubre de 2019 a las 2:18
-
Eliminé el molde innecesario, agregué una variable para la longitud del búfer y cambié
fp
parafilePointer
para mayor claridad.– robo
6 de enero de 2020 a las 11:13
-
Debería ser const int bufferLength si es pedante 🙂
– baz
12 de noviembre de 2021 a las 20:34
gsamaras
Una completa, fgets()
solución:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 256
int main(void)
{
FILE* fp;
fp = fopen("file.txt", "r");
if (fp == NULL) {
perror("Failed: ");
return 1;
}
char buffer[MAX_LEN];
while (fgets(buffer, MAX_LEN, fp))
{
// Remove trailing newline
buffer[strcspn(buffer, "\n")] = 0;
printf("%s\n", buffer);
}
fclose(fp);
return 0;
}
Producción:
First line of file
Second line of file
Third (and also last) line of file
Recuerde, si desea leer desde la entrada estándar (en lugar de un archivo como en este caso), todo lo que tiene que hacer es pasar stdin
como el tercer parámetro de fgets()
método, así:
while(fgets(buffer, MAX_LEN, stdin))
Apéndice
Eliminar el carácter de nueva línea final de la entrada fgets ()
como detectar un archivo esta abierto o no en c
-
Hola @gsamaras creo que directamente podemos pasar
MAX_LEN
a fgets. Encontré esta pieza de descripción en: linux.die.net/man/3/fgets “` “`– usuario10277898
17 de noviembre de 2020 a las 10:23
-
Oye @juancortez, me paso
MAX_LEN - 1
en el segundo argumento del método de hecho!– gsamaras
17 de noviembre de 2020 a las 19:36
-
No hay necesidad de la
-1
enMAX_LEN - 1
fgets(buffer, n, fp) ya lee hasta n-1 caracteres reservando espacio para la terminación nula.– マルちゃん だよ
26 de noviembre de 2021 a las 13:46
-
@マルちゃん だよ Sí, tienes razón cplusplus.com/reference/cstdio/fgetsrespuesta actualizada.
– gsamaras
28 de noviembre de 2021 a las 8:49
RevoLab
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");
//check if file exists
if (fh == NULL){
printf("file does not exists %s", filename);
return 0;
}
//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL) {
printf(line);
}
free(line); // dont forget to free heap memory
Gilles ‘SO- deja de ser malvado’
En tus readLine
función, devuelve un puntero a la line
matriz (estrictamente hablando, un puntero a su primer carácter, pero la diferencia es irrelevante aquí). Dado que es una variable automática (es decir, está “en la pila”), la memoria se recupera cuando la función regresa. Ves galimatías porque printf
ha puesto sus propias cosas en la pila.
Debe devolver un búfer asignado dinámicamente desde la función. Ya tienes uno, es lineBuffer
; todo lo que tiene que hacer es truncarlo a la longitud deseada.
lineBuffer[count] = '\0';
realloc(lineBuffer, count + 1);
return lineBuffer;
}
AGREGADO (respuesta a la pregunta de seguimiento en el comentario): readLine
devuelve un puntero a los caracteres que componen la línea. Este puntero es lo que necesita para trabajar con el contenido de la línea. También es lo que debes pasar a free
cuando hayas terminado de usar la memoria tomada por estos personajes. Así es como puede usar el readLine
función:
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
You can't use the value of `line` again (though you can assign a new value
to the `line` variable if you want). */
-
@Iron: He agregado algo a mi respuesta, pero no estoy seguro de cuál es su dificultad, por lo que puede estar fuera de lugar.
– Gilles ‘SO- deja de ser malvado’
17 de agosto de 2010 a las 11:53
-
@Iron: la respuesta es que no lo liberas. Usted documenta (en la documentación de la API) el hecho de que el búfer devuelto está malloc’d y la persona que llama debe liberarlo. Luego, las personas que usan su función readLine (¡con suerte!) escribirán un código similar al fragmento que Gilles ha agregado a su respuesta.
– JeremyP
17 de agosto de 2010 a las 12:27
Akhil V Suku
Aquí están mis varias horas… Leyendo todo el archivo línea por línea.
char * readline(FILE *fp, char *buffer)
{
int ch;
int i = 0;
size_t buff_len = 0;
buffer = malloc(buff_len + 1);
if (!buffer) return NULL; // Out of memory
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
{
buff_len++;
void *tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL)
{
free(buffer);
return NULL; // Out of memory
}
buffer = tmp;
buffer[i] = (char) ch;
i++;
}
buffer[i] = '\0';
// Detect end
if (ch == EOF && (i == 0 || ferror(fp)))
{
free(buffer);
return NULL;
}
return buffer;
}
void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
puts(s);
free(s);
printf("\n");
}
}
int main()
{
char *fileName = "input-1.txt";
FILE* file = fopen(fileName, "r");
lineByline(file);
return 0;
}
-
@Iron: He agregado algo a mi respuesta, pero no estoy seguro de cuál es su dificultad, por lo que puede estar fuera de lugar.
– Gilles ‘SO- deja de ser malvado’
17 de agosto de 2010 a las 11:53
-
@Iron: la respuesta es que no lo liberas. Usted documenta (en la documentación de la API) el hecho de que el búfer devuelto está malloc’d y la persona que llama debe liberarlo. Luego, las personas que usan su función readLine (¡con suerte!) escribirán un código similar al fragmento que Gilles ha agregado a su respuesta.
– JeremyP
17 de agosto de 2010 a las 12:27
Escapar de Raku
Usar fgets()
para leer una línea de un identificador de archivo.
Usar
fgets
en vez defgetc
. Estás leyendo carácter por carácter en lugar de línea por línea.– Puñal
17 de marzo de 2017 a las 4:00
Tenga en cuenta que
getline()
es parte de POSIX 2008. Puede haber plataformas similares a POSIX sin él, especialmente si no son compatibles con el resto de POSIX 2008, pero dentro del mundo de los sistemas POSIX,getline()
es bastante portátil en estos días.–Jonathan Leffler
8 mayo 2017 a las 21:20