txt - leer un archivo y guardarlo en un arreglo c
C leer archivo línea por línea (14)
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 con printf veo que la cadena constLine también se leyó correctamente.
Sin embargo, si uso la función por ejemplo de esta manera:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s/n", line);
}
printf produce galimatías. ¿Por qué?
Algunas cosas mal con el ejemplo:
- olvidó agregar / n a sus printfs. También los mensajes de error deberían ir a stderr, es decir,
fprintf(stderr, ....
- (no es un biggy sino) considere usar
fgetc()
lugar degetc()
.getc()
es una macro,fgetc()
es una función adecuada -
getc()
devuelve unint
para quech
se declare como unint
. Esto es importante ya que la comparación conEOF
se manejará correctamente. Algunos juegos de caracteres de 8 bits usan0xFF
como un carácter válido (ISO-LATIN-1 sería un ejemplo) yEOF
que es -1, será0xFF
si se asigna a unchar
. Existe un potencial desbordamiento de búfer en la línea
lineBuffer[count] = ''/0'';
Si la línea tiene exactamente 128 caracteres, el
count
es 128 en el punto que se ejecuta.Como otros han señalado, la
line
es una matriz declarada localmente. No puedes devolver un puntero a él.strncpy(count + 1)
copiará a lo sumocount + 1
caracteres pero terminará si golpea''/0''
Debido a que configuralineBuffer[count]
a''/0''
usted sabe que nuncacount + 1
. Sin embargo, si lo hiciera, no pondría un''/0''
terminación, por lo que debe hacerlo. A menudo ves algo como lo siguiente:char buffer [BUFFER_SIZE]; strncpy(buffer, sourceString, BUFFER_SIZE - 1); buffer[BUFFER_SIZE - 1] = ''/0'';
si
malloc()
una línea para devolver (en lugar de su matriz de caracteres local), su tipo de devolución debe serchar*
- soltar laconst
.
Aquí están mis muchas 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;
}
Comete el error de devolver un puntero a una variable automática. La línea variable se asigna en la pila y solo vive mientras viva la función. No se le permite devolver un puntero, ya que tan pronto como regrese la memoria se dará en otro lugar.
const char* func x(){
char line[100];
return (const char*) line; //illegal
}
Para evitar esto, devuelve un puntero a la memoria que reside en el montón, por ejemplo. lineBuffer y debe ser responsabilidad del usuario llamar a free () cuando haya terminado con él. Alternativamente, puede pedirle al usuario que le transmita como argumento una dirección de memoria en la que escribir el contenido de la línea.
Debe usar las funciones de ANSI para leer una línea, ej. Fgets. Después de llamar, necesita el contexto de llamada gratuita (), por ejemplo:
...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...
const char *readLine(FILE *file)
{
char *lineBuffer=calloc(1,1), line[128];
if ( !file || !lineBuffer )
{
fprintf(stderr,"an ErrorNo 1: ...");
exit(1);
}
for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
{
if( strchr(line,''/n'') ) *strchr(line,''/n'')=0;
lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
if( !lineBuffer )
{
fprintf(stderr,"an ErrorNo 2: ...");
exit(2);
}
}
return lineBuffer;
}
En su función readLine
, devuelve un puntero a la matriz line
(Estrictamente hablando, un puntero a su primer carácter, pero la diferencia es irrelevante aquí). Como es una variable automática (es decir, está "en la pila"), la memoria se recupera cuando la función vuelve. Ves galimatías porque printf
ha puesto sus propias cosas en la pila.
Debe devolver un búfer dinámicamente asignado de la función. Ya tienes uno, es lineBuffer
; todo lo que tienes 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 comentario): readLine
devuelve un puntero a los caracteres que componen la línea. Este puntero es lo que necesita para trabajar con los contenidos de la línea. También es lo que debe pasar a free
cuando haya terminado de usar la memoria tomada por estos personajes. A continuación, le mostramos cómo puede usar la función readLine
:
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). */
Implementar método para leer y obtener contenido de un archivo (input1.txt)
#include <stdio.h>
#include <stdlib.h>
void testGetFile() {
// open file
FILE *fp = fopen("input1.txt", "r");
size_t len = 255;
// need malloc memory for line, if not, segmentation fault error will occurred.
char *line = malloc(sizeof(char) * len);
// check if file exist (and you can open it) or not
if (fp == NULL) {
printf("can open file input1.txt!");
return;
}
while(fgets(line, len, fp) != NULL) {
printf("%s/n", line);
}
free(line);
}
Espero que esto ayude. Feliz codificación!
Quiero un código de la base 0 así que hice esto para leer el contenido de la palabra del diccionario línea por línea.
char temp_str [20]; // puede cambiar el tamaño del búfer según sus requisitos Y la longitud de una sola línea en un archivo.
Tenga en cuenta que he inicializado el búfer con carácter nulo cada vez que leo una línea. Esta función puede automatizarse, pero dado que necesito una prueba de concepto y quiero diseñar un programa, Byte Byte
#include<stdio.h>
int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
i=0;
char temp_str[20]={''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0'',''/0''};
while(temp_ch!=''/n'')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
i++;
}
if(temp_ch==''/n'')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}
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 la función getline()
(consulte la página del manual here ):
#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);
}
Use fgets()
para leer una línea de un manejador de archivo.
readLine()
devuelve el puntero a la variable local, lo que causa un comportamiento indefinido.
Para moverte, puedes:
- Crear variable en la función de llamada y pasar su dirección a
readLine()
- Asignar memoria para la
line
usandomalloc()
- en este caso laline
será persistente - Usar variable global, aunque generalmente es una mala práctica
//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
FILE* fp;
char buffer[255];
fp = fopen("file.txt", "r");
while(fgets(buffer, 255, (FILE*) fp)) {
printf("%s/n", buffer);
}
fclose(fp);
const char *readLine(FILE *file, char* line) {
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);
return line;
}
char linebuffer[256];
while (!feof(myFile)) {
const char *line = readLine(myFile, linebuffer);
printf("%s/n", line);
}
tenga en cuenta que la variable ''line'' se declara en la función de llamada y luego se pasa, por lo que su función readLine
llena el buffer predefinido y simplemente lo devuelve. Esta es la forma en que funcionan la mayoría de las bibliotecas C
Hay otras formas, que yo conozco:
- definiendo la
char line[]
como estática (static char line[MAX_LINE_LENGTH]
-> mantendrá su valor DESPUÉS de regresar de la función). -> malo, la función no es reentrante, y la condición de carrera puede ocurrir -> si la llamas dos veces desde dos hilos, sobrescribirá los resultados -
malloc()
ing la línea de caracteres [], y la liberación en funciones de llamada -> demasiados costososmalloc
y, delegando la responsabilidad de liberar el búfer a otra función (la solución más elegante es llamar amalloc
yfree
en cualquier búfer en la misma función)
Por cierto, la conversión ''explícita'' de char*
a const char*
es redundante.
btw2, no es necesario malloc()
el lineBuffer, simplemente char lineBuffer[128]
como char lineBuffer[128]
, por lo que no necesita liberarlo
btw3 no use "matrices de pila de tamaño dinámico" (que define la matriz como char arrayName[some_nonconstant_variable]
), si no sabe exactamente qué está haciendo, solo funciona en C99.
void readLine(FILE* file, char* line, int limit)
{
int i;
int read;
read = fread(line, sizeof(char), limit, file);
line[read] = ''/0'';
for(i = 0; i <= read;i++)
{
if(''/0'' == line[i] || ''/n'' == line[i] || ''/r'' == line[i])
{
line[i] = ''/0'';
break;
}
}
if(i != read)
{
fseek(file, i - read + 1, SEEK_CUR);
}
}
¿Qué hay de este?