Read a file line by line: Difference between revisions
(→{{header|C}}: +{{libheader|BSD}} for fgetln() solution.) |
m (→{{header|C}}: Changed {{libheader|BSD}} to {{libheader|BSD libc}} before I create the category.) |
||
Line 98: | Line 98: | ||
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. |
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. |
||
{{libheader|BSD}} |
{{libheader|BSD libc}} |
||
{{works with|OpenBSD|4.8}} |
{{works with|OpenBSD|4.8}} |
||
Revision as of 22:14, 18 April 2011
You are encouraged to solve this task according to the task description, using any language you may know.
The task is to demonstrate how to read a file line by line (as opposed to reading the entire file).
See also: Input loop.
Ada
line_by_line.adb: <lang Ada>with Ada.Text_IO; procedure Line_By_Line is
Filename : String := "line_by_line.adb"; File : Ada.Text_IO.File_Type; Line_Count : Natural := 0;
begin
Ada.Text_IO.Open (File => File, Mode => Ada.Text_IO.In_File, Name => Filename); while not Ada.Text_IO.End_Of_File (File) loop declare Line : String := Ada.Text_IO.Get_Line (File); begin Line_Count := Line_Count + 1; Ada.Text_IO.Put_Line (Natural'Image (Line_Count) & ": " & Line); end; end loop; Ada.Text_IO.Close (File);
end Line_By_Line;</lang>
Output:
1: with Ada.Text_IO; 2: procedure Line_By_Line is 3: Filename : String := "line_by_line.adb"; 4: File : Ada.Text_IO.File_Type; 5: Line_Count : Natural := 0; 6: begin 7: Ada.Text_IO.Open (File => File, 8: Mode => Ada.Text_IO.In_File, 9: Name => Filename); 10: while not Ada.Text_IO.End_Of_File (File) loop 11: declare 12: Line : String := Ada.Text_IO.Get_Line (File); 13: begin 14: Line_Count := Line_Count + 1; 15: Ada.Text_IO.Put_Line (Natural'Image (Line_Count) & ": " & Line); 16: end; 17: end loop; 18: Ada.Text_IO.Close (File); 19: end Line_By_Line;
AutoHotkey
<lang AutoHotkey>; --> Prompt the user to select the file being read
FileSelectFile, File, 1, %A_ScriptDir%, Select the (text) file to read, Documents (*.txt) ; Could of course be set to support other filetypes If Errorlevel ; If no file selected ExitApp
- --> Main loop
- Input (File), Output (Text)
Loop { FileReadLine, Line, %File%, %A_Index% ; Reads line N (where N is loop iteration) if Errorlevel ; If line does not exist, break loop break Text .= A_Index ". " Line . "`n" ; Appends the line to the variable "Text", adding line number before & new line after }
- --> Delivers the output as a text file
FileDelete, Output.txt ; Makes sure output is clear before writing FileAppend, %Text%, Output.txt ; Writes the result to Output.txt Run Output.txt ; Shows the created file</lang>
BASIC
ZX Spectrum Basic
The tape recorder interface does not support fragmented reads, because tape recorder start and stop is not atomic, (and a leadin is required for tape input). However, the microdrive does support fragmented reads. In the following example, we read a file line by line from a file on microdrive 1.
<lang basic> 10 REM open my file for input 20 OPEN #4;"m";1;"MYFILE": REM stream 4 is the first available for general purpose 30 INPUT #4; LINE a$: REM a$ will hold our line from the file 40 REM because we do not know how many lines are in the file, we need an error trap 50 REM to gracefully exit when the file is read. (omitted from this example) 60 REM to prevent an error at end of file, place a handler here 100 GOTO 30 </lang>
Brat
<lang brat>include :file
file.each_line "foobar.txt" { line |
p line
}</lang>
C
This is not easy to do, because the C library is so primitive. There is 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 fgetln() and err() from BSD, but will not work with most other systems.
<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>
C#
'File.ReadLines' reads the lines of a file which could easily bee stepped through. <lang csharp>foreach (string readLine in File.ReadLines("FileName")
DoSomething(readLine);</lang>
A full code may look like; <lang csharp>using System; using System.IO; using System.Text;
namespace RosettaCode {
internal class Program { private static void Main() { var sb = new StringBuilder(); string F = "File.txt";
// Read a file, line by line. try { foreach (string readLine in File.ReadLines(F)) { // Use the data in some way... sb.Append(readLine); sb.Append("\n"); } } catch (Exception exception) { Console.WriteLine(exception.Message); Environment.Exit(1); }
// Preset the results Console.WriteLine(sb.ToString()); } }
}</lang>
D
<lang d>import std.stdio;
void main() {
foreach (line; File("foobar.txt").byLine()) write(line);
}</lang> The File is managed by reference count, and it gets closed when it gets out of scope or it changes. The 'line' is a char[] (with newline), so if you need a string you have to idup it.
Forth
<lang forth>4096 constant max-line
- read-lines
begin stdin pad max-line read-line throw while pad swap \ addr len is the line of data, excluding newline 2drop repeat ;</lang>
J
J currently discourages this "read just one line" approach. In addition to the arbitrary character of lines, there are issues of problem size and scope (what x happens when you have a billion characters between your newline delimiters?). Usually, it's easier to just read the entire file, or memory map the file, and when files are so large that that is not practical it's probably better to put the programmer in explicit control of issues like block sizes and exception handling.
This implementation looks for lines separated by ascii character 10. Lines returned here do not include the line separater character. Files with no line-separating character at the end are treated as well formed -- if the last character of the file is the line separator that means that you have an empty line at the end of the file.
This implementation does nothing special when dealing with multi-gigabyte lines. If you encounter an excessively large line and if do not have enough physical memory, your system will experience heavy memory pressure. If you also do not have enough virtual memory to hold a line you will get an out of memory exception.
<lang j>cocurrent 'linereader'
NB. configuration parameter blocksize=: 400000
NB. implementation offset=: 0 position=: 0 buffer=: lines=:
create=: monad define name=: boxxopen y size=: 1!:4 name blocks=: 2 <@(-~/\)\ ~. size <. blocksize * i. 1 + >. size % blocksize )
readblocks=: monad define if. 0=#blocks do. return. end. if. 1<#lines do. return. end. whilst. -.LF e.chars do. buffer=: buffer,chars=. 1!:11 name,{.blocks blocks=: }.blocks lines=: <;._2 buffer,LF end. buffer=: _1{::lines )
next=: monad define if. (#blocks)*.2>#lines do. readblocks end. r=. 0{::lines lines=: }.lines r )</lang>
<lang j> example=: '/tmp/example.txt' conew 'linereader'
next__example
this is line 1
next__example
and this is line 2</lang>
Logo
There are several words which will return a line of input.
- readline - returns a line as a list of words
- readword - returns a line as a single word, or an empty list if it reached the end of file
- readrawline - returns a line as a single word, with no characters escaped
<lang logo>while [not eof?] [print readline]</lang>
Lua
<lang lua>filename = "input.txt" fp = io.open( filename, "r" )
for line in fp:lines() do
print( line )
end
fp:close() </lang>
Objective-C
To read an entire file into a string, you can: <lang objc>NSString *path = [NSString stringWithString:@"/usr/share/dict/words"]; NSError *error = nil; NSString *words = [[NSString alloc] initWithContentsOfFile:path
encoding:NSUTF8StringEncoding error:&error];
</lang>
Use the UTF-8 encoder on ASCII.
Now to get the individual lines, break down the string:
<lang objc>NSArray* lines = [words componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];</lang>
Perl
For the simple case of iterating over the lines of a file you can do: <lang perl>open(FOO, '<', 'foobar.txt') or die $!; while (<FOO>) { # each line is stored in $_, with terminating newline
chomp; # chomp, short for chomp($_), removes the terminating newline process($_);
}
close(FOO);</lang>
The angle bracket operator < >
reads a filehandle line by line. (The angle bracket operator can also be used to open and read from files that match a specific pattern, by putting the pattern in the brackets.)
Without specifying the variable that each line should be put into, it automatically puts it into $_
, which is also conveniently the default argument for many Perl functions. If you wanted to use your own variable, you can do something like this:
<lang perl>open(FOO, '<', 'foobar.txt') or die $!;
while (my $line = <FOO>) {
chomp($line); process($_);
} close(FOO);</lang>
The special use of the angle bracket operator with nothing inside, will read from all files whose names were specified on the command line: <lang perl>while (<>) {
chomp; process($_);
}</lang>
PicoLisp
<lang PicoLisp>(in "foobar.txt"
(while (line) (process @) ) )</lang>
PureBasic
<lang PureBasic>FileName$ = OpenFileRequester("","foo.txt","*.txt",0)
If OpenFile(0, FileName$)
While Not Eof(0) line$ = ReadString(0) DoSomethingWithTheLine(Line) Wend CloseFile(0)
EndIf</lang>
Python
For the simple case of iterating over the lines of a file you can do: <lang python>with open("foobar.txt") as f:
for line in f: process(line)</lang>
The with statement ensures the correct closing of the file after it is processed, and iterating over the file object f
, adjusts what is considered line separator character(s) so the code will work on multiple operating systems such as Windows, Mac, and Solaris without change.
Python also has the fileinput module. This can process multiple files parsed from the command line and can be set to modify files 'in-place'. <lang python>import fileinput for line in fileinput.input():
process(line)
</lang>
Ruby
<lang ruby>IO.foreach "foobar.txt" do |line|
puts line
end</lang>
Tcl
<lang tcl>set f [open "foobar.txt"] while {[gets $f line] >= 0} {
# This loops over every line puts ">>$line<<"
} close $f</lang>
TUSCRIPT
<lang tuscript> $$ MODE TUSCRIPT
datei="rosetta.txt" ERROR/STOP OPEN (datei,READ,-std-)
ACCESS q: READ/RECORDS/UTF8 $datei s,line
LOOP READ/NEXT/EXIT q PRINT line ENDLOOP
ENDACCESS q </lang> or: <lang tuscript> LOOP line=datei
PRINT line
ENDLOOP </lang>
UNIX Shell
<lang sh>cat foobar.txt | while read line ; do
# This loop repeats for each line of the file echo "$line"
done</lang>
Visual Basic
<lang vb>' Read lines from a file ' ' (c) Copyright 1993 - 2011 Mark Hobley ' ' This code was ported from an application program written in Microsoft Quickbasic ' ' This code can be redistributed or modified under the terms of version 1.2 of ' the GNU Free Documentation Licence as published by the Free Software Foundation.
Sub readlinesfromafile()
var.filename = "foobar.txt" var.filebuffersize = ini.inimaxlinelength Call openfileread If flg.error = "Y" Then flg.abort = "Y" Exit Sub End If If flg.exists <> "Y" Then flg.abort = "Y" Exit Sub End If
readfilelabela:
Call readlinefromfile If flg.error = "Y" Then flg.abort = "Y" Call closestream flg.error = "Y" Exit Sub End If If flg.endoffile <> "Y" Then ' We have a line from the file Print message$ GoTo readfilelabela End If ' End of file reached ' Close the file and exit Call closestream Exit Sub
End Sub
Sub openfileread()
flg.streamopen = "N" Call checkfileexists If flg.error = "Y" Then Exit Sub If flg.exists <> "Y" Then Exit Sub Call getfreestream If flg.error = "Y" Then Exit Sub var.errorsection = "Opening File" var.errordevice = var.filename If ini.errortrap = "Y" Then On Local Error GoTo openfilereaderror End If flg.endoffile = "N" Open var.filename For Input As #var.stream Len = var.filebuffersize flg.streamopen = "Y" Exit Sub
openfilereaderror:
var.errorcode = Err Call errorhandler resume '!!
End Sub
Public Sub checkfileexists()
var.errorsection = "Checking File Exists" var.errordevice = var.filename If ini.errortrap = "Y" Then On Local Error GoTo checkfileexistserror End If flg.exists = "N" If Dir$(var.filename, 0) <> "" Then flg.exists = "Y" End If Exit Sub
checkfileexistserror:
var.errorcode = Err Call errorhandler
End Sub
Public Sub getfreestream()
var.errorsection = "Opening Free Data Stream" var.errordevice = "" If ini.errortrap = "Y" Then On Local Error GoTo getfreestreamerror End If var.stream = FreeFile Exit Sub
getfreestreamerror:
var.errorcode = Err Call errorhandler resume '!!
End Sub
Sub closestream()
If ini.errortrap = "Y" Then On Local Error GoTo closestreamerror End If var.errorsection = "Closing Stream" var.errordevice = "" flg.resumenext = "Y" Close #var.stream If flg.error = "Y" Then flg.error = "N" '!! Call unexpectederror End If flg.streamopen = "N" Exit Sub
closestreamerror:
var.errorcode = Err Call errorhandler resume next
End Sub
Public Sub errorhandler()
tmp$ = btrim$(var.errorsection) tmp2$ = btrim$(var.errordevice) If tmp2$ <> "" Then tmp$ = tmp$ + " (" + tmp2$ + ")" End If tmp$ = tmp$ + " : " + Str$(var.errorcode) tmp1% = MsgBox(tmp$, 0, "Error!") flg.error = "Y" If flg.resumenext = "Y" Then flg.resumenext = "N"
' Resume Next
Else flg.error = "N"
' Resume
End If
End Sub
Public Function btrim$(arg$)
btrim$ = LTrim$(RTrim$(arg$))
End Function</lang>