Jump to content

Read a file line by line: Difference between revisions

Line 9:
file.each_line "foobar.txt" { line |
p line
}</lang>
 
=={{header|C}}==
This is not easy to do, because the C library is so primitive. There is [http://www.openbsd.org/cgi-bin/man.cgi?query=fgets&apropos=0&sektion=3&manpath=OpenBSD+Current&arch=i386&format=html ''fgets()''], but this function limits the length of a line. ''fgets()'' also loses characters if there is a NUL character '\0' in the middle of a line.
 
The next example uses [http://www.openbsd.org/cgi-bin/man.cgi?query=fgetln&apropos=0&sektion=3&manpath=OpenBSD+Current&arch=i386&format=html ''fgetln()''] and [http://www.openbsd.org/cgi-bin/man.cgi?query=err&apropos=0&sektion=3&manpath=OpenBSD+Current&arch=i386&format=html ''err()''] from [[BSD]], but will not work with most other systems.
 
{{works with|OpenBSD|4.8}}
 
<lang c>#include <err.h> /* err */
#include <stdio.h> /* fopen, fgetln, fputs, fwrite */
 
/*
* Read a file line by line.
* http://rosettacode.org/wiki/Read_a_file_line_by_line
*/
int
main()
{
FILE *f;
size_t len;
char *line;
 
f = fopen("foobar.txt", "r");
if (f == NULL)
err(1, "foobar.txt");
 
/*
* This loop reads each line.
* Remember that line is not a C string.
* There is no terminating '\0'.
*/
while (line = fgetln(f, &len)) {
/*
* Do something with line.
*/
fputs("LINE: ", stdout);
fwrite(line, len, 1, stdout);
}
if (!feof(f))
err(1, "fgetln");
 
return 0;
}</lang>
 
For other systems, you can code something like ''fgetln()''. The next example refactors the code from [[Synchronous concurrency#C]] that reads lines.
 
<lang c>#include <stdlib.h> /* exit, malloc, realloc, free */
#include <stdio.h> /* fopen, fgetc, fputs, fwrite */
 
struct line_reader {
/* All members are private. */
FILE *f;
char *buf;
size_t siz;
};
 
/*
* Initializes a line reader _lr_ for the stream _f_.
*/
void
lr_init(struct line_reader *lr, FILE *f)
{
lr->f = f;
lr->buf = NULL;
}
 
/*
* Reads the next line. If successful, returns a pointer to the line,
* and sets *len to the number of characters, at least 1. The result is
* _not_ a C string; it has no terminating '\0'. The returned pointer
* remains valid until the next call to next_line() or lr_free() with
* the same _lr_.
*
* If not successful, returns NULL. This can mean an end of file,
* an error on the stream, or an error of memory allocation.
*/
char *
next_line(struct line_reader *lr, size_t *len)
{
size_t newsiz;
int c;
char *newbuf;
 
if (lr->buf == NULL) {
/* New buffer. */
lr->buf = malloc(4096);
if (lr->buf == NULL)
return NULL;
lr->siz = 4096;
}
 
*len = 0; /* Start with empty line. */
for (;;) {
c = fgetc(lr->f); /* Read next character. */
if (ferror(lr->f))
return NULL;
 
if (c == EOF) {
/*
* End of file is also end of line,
` * unless the line would be empty.
*/
if (*len == 0)
return NULL;
else
return lr->buf;
} else {
/* Append c to the buffer. */
if (*len == lr->siz) {
/* Need a bigger buffer! */
newsiz = lr->siz * 2;
newbuf = realloc(lr->buf, newsiz);
if (newbuf == NULL)
return NULL;
lr->buf = newbuf;
lr->siz = newsiz;
}
lr->buf[(*len)++] = c;
 
/* '\n' is end of line. */
if (c == '\n')
return lr->buf;
}
}
}
 
/*
* Frees memory used by _lr_.
*/
void
lr_free(struct line_reader *lr)
{
free(lr->buf);
lr->buf = NULL;
}
 
/*
* Read a file line by line.
* http://rosettacode.org/wiki/Read_a_file_line_by_line
*/
int
main()
{
struct line_reader lr;
FILE *f;
size_t len;
char *line;
 
f = fopen("foobar.txt", "r");
if (f == NULL) {
perror("foobar.txt");
exit(1);
}
 
/*
* This loop reads each line.
* Remember that line is not a C string.
* There is no terminating '\0'.
*/
lr_init(&lr, f);
while (line = next_line(&lr, &len)) {
/*
* Do something with line.
*/
fputs("LINE: ", stdout);
fwrite(line, len, 1, stdout);
}
if (!feof(f)) {
perror("next_line");
exit(1);
}
lr_free(&lr);
 
return 0;
}</lang>
 
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.