Read a specific line from a file: Difference between revisions
No edit summary |
|||
Line 1,115: | Line 1,115: | ||
(call-with-input-file "some-file" |
(call-with-input-file "some-file" |
||
(λ(i) (for/last ([line (in-lines i)] [n 7]) line)))) |
(λ(i) (for/last ([line (in-lines i)] [n 7]) line)))) |
||
</lang> |
|||
=={{header|Rebol}}== |
|||
<lang rebol> |
|||
x: pick read/lines request-file/only 7 |
|||
either x [print x] [print "No seventh line"] |
|||
</lang> |
</lang> |
||
Revision as of 04:00, 25 December 2014
You are encouraged to solve this task according to the task description, using any language you may know.
Some languages have special semantics for obtaining a known line number from a file. The task is to demonstrate how to obtain the contents of a specific line within a file. For the purpose of this task demonstrate how the contents of the seventh line of a file can be obtained, and store it in a variable or in memory (for potential future use within the program if the code were to become embedded). If the file does not contain seven lines, or the seventh line is empty, or too big to be retrieved, output an appropriate message. If no special semantics are available for obtaining the required line, it is permissible to read line by line. Note that empty lines are considered and should still be counted. Note that for functional languages or languages without variables or storage, it is permissible to output the extracted data to standard output.
Ada
A github repository was created for this solution https://github.com/mulander/read_a_specific_line_from_a_file
The repository contains test cases for specific file types the program might be run against.
Based on the task description the following requirements were identified
- Display a specific message for a file having fewer than 7 lines
- Display a specific message if the 7th line is empty
- Display a specific message if the 7th line is too big to be retrieved and stored in memory
- Acquire the 7th line of a file, using built-in language features/standard libraries if accessible
- Store the retrieved line in a variable/memory location
The following undefined behavior was identified and addressed
- The task description does not define an empty line. The program assumes that an empty line contains only a line break character. A line containing whitespace (' ', '\t') is not considered empty.
- Things considered an error in execution are printed out to stderr
- In case of an encountered error the return code of the program is changed to Failure (1)
In order to ease testing - the program expects the file name to be provided as the first argument on the command line.
Additional checks are performed by the program
- Tests if the file name was provided on the command line
- Tests if the it is possible to open the provided file with read access
<lang ada>with Ada.Command_Line,
Ada.Text_IO;
procedure Rosetta_Read is
use Ada.Command_Line, Ada.Text_IO;
Source : File_Type;
begin
if Argument_Count /= 1 then Put_Line (File => Standard_Error, Item => "Usage: " & Command_Name & " file_name"); Set_Exit_Status (Failure); return; end if;
declare File_Name : String renames Argument (Number => 1); begin Open (File => Source, Mode => In_File, Name => File_Name); exception when others => Put_Line (File => Standard_Error, Item => "Can not open '" & File_Name & "'."); Set_Exit_Status (Failure); return; end;
Set_Line (File => Source, To => 7);
declare Line_7 : constant String := Get_Line (File => Source); begin if Line_7'Length = 0 then Put_Line ("Line 7 is empty."); else Put_Line (Line_7); end if; end;
exception
when End_Error => Put_Line (File => Standard_Error, Item => "The file contains fewer than 7 lines."); Set_Exit_Status (Failure); return; when Storage_Error => Put_Line (File => Standard_Error, Item => "Line 7 is too long to load."); Set_Exit_Status (Failure); return;
end Rosetta_Read;</lang>
Aime
<lang aime>void read_line(text &line, text path, integer n) {
file f;
f_affix(f, path);
while (n) {
n -= 1; f_slip(f);
}
f_line(f, line);
}
integer
main(void)
{
if (2 < argc()) {
text line;
read_line(line, argv(1), 6);
o_text(line); o_byte('\n');
}
return 0;
}</lang>
ALGOL 68
<lang algol68># reads the line with number "number" (counting from 1) #
- from the file named "file name" and returns the text of the #
- in "line". If an error occurs, the result is FALSE and a #
- message is returned in "err". If no error occurs, TRUE is #
- returned #
PROC read specific line = ( STRING file name
, INT number # line 7 # , REF STRING line , REF STRING err )BOOL:
BEGIN
FILE input file;
line := ""; err := "";
IF open( input file, file name, stand in channel ) /= 0 THEN # failed to open the file # err := "Unable to open """ + file name + """"; FALSE
ELSE # file opened OK #
BOOL at eof := FALSE;
# set the EOF handler for the file # on logical file end( input file , ( REF FILE f )BOOL: BEGIN # note that we reached EOF on the # # latest read # at eof := TRUE;
# return TRUE so processing can continue # TRUE END );
INT line number := 0; STRING text;
WHILE line number < number AND NOT at eof DO
get( input file, ( text, newline ) ); line number +:= 1
OD;
# close the file # close( input file );
# return the line or an error message depending on whether # # we got a line with the required number or not # IF line number = number THEN # got the required line # line := text; TRUE ELSE # not enough lines in the file # err := """" + file name + """ is too short"; FALSE FI
FI
END; # read specific line #
main:(
# read the seventh line of this source and print it # # (or an error message if we can't) #
STRING line; STRING err;
IF read specific line( "read-specific-line.a68", 7, line, err ) THEN # got the line # print( ( "line seven is: """ + line + """", newline ) ) ELSE # got an error # print( ( "unable to read line: """ + err + """" ) ) FI
)</lang>
- Output:
line seven is: " , INT number # line 7 #"
AutoHotkey
<lang AutoHotkey>FileReadLine, OutputVar, filename.txt, 7 if ErrorLevel
MsgBox, There was an error reading the 7th line of the file</lang>
AWK
<lang awk>#!/usr/bin/awk -f
- usage: readnthline.awk -v lineno=6 filename
FNR==lineno { storedline=$0; found++ } END {if(found<1){print "ERROR: Line",lineno,"not found"}</lang>
BBC BASIC
<lang bbcbasic> filepath$ = @lib$ + "..\licence.txt"
requiredline% = 7 file% = OPENIN(filepath$) IF file%=0 ERROR 100, "File could not be opened" FOR i% = 1 TO requiredline% IF EOF#file% ERROR 100, "File contains too few lines" INPUT #file%, text$ NEXT CLOSE #file% IF ASCtext$=10 text$ = MID$(text$,2) PRINT text$</lang>
C
Mmap file and search for offsets to certain line number. Since mapped file really is memory, there's no extra storage procedure once offsets are found. <lang c>#include <unistd.h>
- include <sys/types.h>
- include <sys/mman.h>
- include <sys/stat.h>
- include <fcntl.h>
- include <err.h>
/* following code assumes all file operations succeed. In practice,
* return codes from open, close, fstat, mmap, munmap all need to be * checked for error.
- /
int read_file_line(const char *path, int line_no) { struct stat s; char *buf; off_t start = -1, end = -1; size_t i; int ln, fd, ret = 1;
if (line_no == 1) start = 0; else if (line_no < 1){ warn("line_no too small"); return 0; /* line_no starts at 1; less is error */ }
line_no--; /* back to zero based, easier */
fd = open(path, O_RDONLY); fstat(fd, &s);
/* Map the whole file. If the file is huge (up to GBs), OS will swap * pages in and out, and because search for lines goes sequentially * and never accesses more than one page at a time, penalty is low. * If the file is HUGE, such that OS can't find an address space to map * it, we got a real problem. In practice one would repeatedly map small * chunks, say 1MB at a time, and find the offsets of the line along the * way. Although, if file is really so huge, the line itself can't be * guaranteed small enough to be "stored in memory", so there. */ buf = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
/* optional; if the file is large, tell OS to read ahead */ madvise(buf, s.st_size, MADV_SEQUENTIAL);
for (i = ln = 0; i < s.st_size && ln <= line_no; i++) { if (buf[i] != '\n') continue;
if (++ln == line_no) start = i + 1; else if (ln == line_no + 1) end = i + 1; }
if (start >= s.st_size || start < 0) { warn("file does not have line %d", line_no + 1); ret = 0; } else { /* do something with the line here, like write(STDOUT_FILENO, buf + start, end - start); or copy it out, or something */ }
munmap(buf, s.st_size); close(fd);
return ret; }</lang>
Alternate Version
This version does not rely on POSIX APIs such as mmap, but rather sticks to ANSI C functionality. This version also works with non-seekable files, so it can be fed by a pipe. It performs limited but adequate error checking. That is, get_nth_line returns NULL on all failures, and the caller can distinguish EOF, file read error and out of memory by calling feof() and ferror() on the input file.
<lang c>#include <stdio.h>
- include <stdlib.h>
- define BUF_SIZE ( 256 )
char *get_nth_line( FILE *f, int line_no ) {
char buf[ BUF_SIZE ]; size_t curr_alloc = BUF_SIZE, curr_ofs = 0; char *line = malloc( BUF_SIZE ); int in_line = line_no == 1; size_t bytes_read;
/* Illegal to ask for a line before the first one. */ if ( line_no < 1 ) return NULL;
/* Handle out-of-memory by returning NULL */ if ( !line ) return NULL;
/* Scan the file looking for newlines */ while ( line_no && ( bytes_read = fread( buf, 1, BUF_SIZE, f ) ) > 0 ) { int i;
for ( i = 0 ; i < bytes_read ; i++ ) { if ( in_line ) { if ( curr_ofs >= curr_alloc ) { curr_alloc <<= 1; line = realloc( line, curr_alloc );
if ( !line ) /* out of memory? */ return NULL; } line[ curr_ofs++ ] = buf[i]; }
if ( buf[i] == '\n' ) { line_no--;
if ( line_no == 1 ) in_line = 1; if ( line_no == 0 ) break; } } }
/* Didn't find the line? */ if ( line_no != 0 ) { free( line ); return NULL; }
/* Resize allocated buffer to what's exactly needed by the string and the terminating NUL character. Note that this code *keeps* the terminating newline as part of the string. */ line = realloc( line, curr_ofs + 1 ); if ( !line ) /* out of memory? */ return NULL;
/* Add the terminating NUL. */ line[ curr_ofs ] = '\0';
/* Return the line. Caller is responsible for freeing it. */ return line;
}
/* Test program. Prints out the 7th line of input from stdin, if any */
int main( int argc, char *argv[] )
{
char *line7 = get_nth_line( stdin, 7 );
if ( line7 ) { printf("The 7th line of input was:\n%s\n", line7 ); free( line7 ); } else { printf("Did not find the 7th line of input. Reason: "); if ( feof( stdin ) ) puts("End of file reached."); else if ( ferror( stdin ) ) puts("Error reading input."); else puts("Out of memory."); }
return 0;
} </lang>
C++
<lang cpp>#include <string>
- include <fstream>
- include <iostream>
int main( ) {
std::cout << "Which file do you want to look at ?\n" ; std::string input ; std::getline( std::cin , input ) ; std::ifstream infile( input.c_str( ) , std::ios::in ) ; std::string file( input ) ; std::cout << "Which file line do you want to see ? ( Give a number > 0 ) ?\n" ; std::getline( std::cin , input ) ; int linenumber = std::stoi( input ) ; int lines_read = 0 ; std::string line ; if ( infile.is_open( ) ) { while ( infile ) {
getline( infile , line ) ; lines_read++ ; if ( lines_read == linenumber ) { std::cout << line << std::endl ; break ; }
} infile.close( ) ; if ( lines_read < linenumber )
std::cout << "No " << linenumber << " lines in " << file << " !\n" ;
return 0 ; } else { std::cerr << "Could not find file " << file << " !\n" ; return 1 ; }
}</lang>
Clojure
<lang clojure>(defn read-nth-line
"Read line-number from the given text file. The first line has the number 1." [file line-number] (with-open [rdr (clojure.java.io/reader file)] (nth (line-seq rdr) (dec line-number))))</lang>
- Output:
user=> (read-nth-line "/tmp/test.txt" 7) "foo"
Common Lisp
<lang lisp>(defun read-nth-line (file n &aux (line-number 0))
"Read the nth line from a text file. The first line has the number 1" (assert (> n 0) (n)) (with-open-file (stream file) (loop for line = (read-line stream nil nil) if (and (null line) (< line-number n)) do (error "file ~a is too short, just ~a, not ~a lines long" file line-number n) do (incf line-number) if (and line (= line-number n)) do (return line))))
</lang>
Example call:
CL-USER> (read-nth-line "/tmp/test1.text" 7) "foo"
C#
<lang C sharp>using System; using System.IO;
namespace GetLine {
internal class Program { private static void Main(string[] args) { Console.WriteLine(GetLine(args[0], uint.Parse(args[1]))); }
private static string GetLine(string path, uint line) { using (var reader = new StreamReader(path)) { try { for (uint i = 0; i <= line; i++) { if (reader.EndOfStream) return string.Format("There {1} less than {0} line{2} in the file.", line, ((line == 1) ? "is" : "are"), ((line == 1) ? "" : "s"));
if (i == line) return reader.ReadLine();
reader.ReadLine(); } } catch (IOException ex) { return ex.Message; } catch (OutOfMemoryException ex) { return ex.Message; } }
throw new Exception("Something bad happened."); } }
}</lang>
D
<lang d>import std.stdio;
void main() {
int countLines; char[] ln; auto f = File("linenumber.d", "r"); foreach (char[] line; f.byLine()) { countLines++; if (countLines == 7) { ln = line; break; } } switch(countLines) { case 0 : writeln("the file has zero length"); break; case 7 : writeln("line 7: ", (ln.length ? ln : "empty")); break; default : writefln("the file only contains %d lines", countLines); }
}</lang>
line 7: foreach (char[] line; f.byLine()) {
Erlang
Using function into_list/1 from Read_a_file_line_by_line. There is no behaviour specified after printing an error message, so I throw an exception. An alternative would be to continue with a default value? <lang Erlang> -module( read_a_specific_line ).
-export( [from_file/2, task/0] ).
from_file( File, N ) -> line_nr( N, read_a_file_line_by_line:into_list(File) ).
task() ->
Lines = read_a_file_line_by_line:into_list( "read_a_specific_line.erl" ), Line_7 = line_nr( 7, Lines ), Line_7.
line_nr( N, Lines ) ->
try case lists:nth( N, Lines ) of "\n" -> erlang:exit( empty_line ) ; Line -> Line end
catch _Type:Error0 -> Error = line_nr_error( Error0 ), io:fwrite( "Error: ~p~n", [Error] ), erlang:exit( Error )
end.
line_nr_error( function_clause ) -> too_few_lines_in_file; line_nr_error( Error ) -> Error. </lang>
- Output:
27> read_a_specific_line:task(). "task() ->\n" 28> read_a_specific_line:from_file("read_a_specific_line.erl", 6). Error: empty_line ** exception exit: empty_line in function read_a_specific_line:line_nr/2 (read_a_specific_line.erl, line 25) 29> read_a_specific_line:from_file("read_a_specific_line.erl", 66). Error: too_few_lines_in_file ** exception exit: too_few_lines_in_file in function read_a_specific_line:line_nr/2 (read_a_specific_line.erl, line 25)
F#
<lang fsharp>open System open System.IO
[<EntryPoint>] let main args =
let n = Int32.Parse(args.[1]) - 1 use r = new StreamReader(args.[0]) let lines = Seq.unfold ( fun (reader : StreamReader) -> if (reader.EndOfStream) then None else Some(reader.ReadLine(), reader)) r let line = Seq.nth n lines // Seq.nth throws an ArgumentException, // if not not enough lines available Console.WriteLine(line) 0</lang>
Go
<lang go>package main
import ( "bufio" "errors" "fmt" "io" "os" )
func main() { if line, err := rsl("input.txt", 7); err == nil { fmt.Println("7th line:") fmt.Println(line) } else { fmt.Println("rsl:", err) } }
func rsl(fn string, n int) (string, error) { if n < 1 { return "", fmt.Errorf("invalid request: line %d", n) } f, err := os.Open(fn) if err != nil { return "", err } defer f.Close() bf := bufio.NewReader(f) var line string for lnum := 0; lnum < n; lnum++ { line, err = bf.ReadString('\n') if err == io.EOF { switch lnum { case 0: return "", errors.New("no lines in file") case 1: return "", errors.New("only 1 line") default: return "", fmt.Errorf("only %d lines", lnum) } } if err != nil { return "", err } } if line == "" { return "", fmt.Errorf("line %d empty", n) } return line, nil }</lang>
Groovy
<lang groovy>def line = null new File("lines.txt").eachLine { currentLine, lineNumber ->
if (lineNumber == 7) { line = currentLine }
} println "Line 7 = $line"</lang>
Haskell
<lang Haskell>main :: IO () main = do contents <- readFile filename
case drop 6 $ lines contents of [] -> error "File has less than seven lines" l:_ -> putStrLn l where filename = "testfile"</lang>
Icon and Unicon
The procedure readline uses repeated alternation (i.e. |read()) to generate the lines of the file one at a time and limitation (i.e. \ n) to limit the generation to n results. If the file is not large enough readline will fail.
While it is certainly possible to read at file at specific offsets without reading each line via seek, with files using line feed terminated variable length records something has to read the data to determine the 7th record. This solution uses a combination of repeated alternation and generation limiting to achieve this. The counter is simply to discover if there are enough records.
<lang Icon>procedure main() write(readline("foo.bar.txt",7)|"failed") end
procedure readline(f,n) # return n'th line of file f f := open(\f,"r") | fail # open file every i := n & line := |read(f) \ n do i -:= 1 # <== here close(f) if i = 0 then return line end</lang>
J
<lang j>readLine=: 4 :0
(x-1) {:: <;.2 ] 1!:1 boxxopen y
)</lang>
Thus: <lang bash>$ cal 2011 > cal.txt</lang>
<lang j> 7 readLine 'cal.txt'
9 10 11 12 13 14 15 13 14 15 16 17 18 19 13 14 15 16 17 18 19</lang>
Note that this code assumes that the last character in the file is the line end character, and that the line end character is a part of the line to be retrieved.
Tacit alternative <lang j>require 'files' NB. required for versions before J701 readLineT=: <:@[ {:: 'b'&freads@]</lang> This is not quite equivalent to the code above as it handles cross-platform line-endings and those line end character(s) are removed from the result.
Java
example: java -cp . LineNbr7 LineNbr7.java
output : line 7: public static void main(String[] args) throws Exception {;
<lang java>package linenbr7;
import java.io.*;
public class LineNbr7 {
public static void main(String[] args) throws Exception { File f = new File(args[0]); if (!f.isFile() || !f.canRead()) throw new IOException("can't read " + args[0]);
BufferedReader br = new BufferedReader(new FileReader(f)); try (LineNumberReader lnr = new LineNumberReader(br)) { String line = null; int lnum = 0; while ((line = lnr.readLine()) != null && (lnum = lnr.getLineNumber()) < 7) { }
switch (lnum) { case 0: System.out.println("the file has zero length"); break; case 7: boolean empty = "".equals(line); System.out.println("line 7: " + (empty ? "empty" : line)); break; default: System.out.println("the file has only " + lnum + " line(s)"); } } }
}</lang>
Julia
The short following snippet of code actually stores all the lines from the file in an array and displays the seventh element of the array, returning an error if there is no such element. Since the array is not referenced, it will be garbage collected when needed. The filehandle is closed upon completion of the task, be it successful or not. <lang Julia>open(readlines, "path/to/file")[7]</lang> The next function reads n lines in the file and displays the last read if possible, or returns a short message. Here again, the filehandle is automatically closed after the task. Note that the first line is returned if a negative number is given as the line number. <lang Julia>function read_nth_lines(stream, num)
for i = 1:num-1 readline(stream) end result = readline(stream) print(result != "" ? result : "No such line.")
end</lang>
- Output:
julia> open(line -> read_nth_lines(line, 7), "path/to/file") "Hi, I am the content of the seventh line\n"
Lasso
<lang Lasso>local(f) = file('unixdict.txt') handle => { #f->close } local(this_line = string,line = 0)
- f->forEachLine => {
#line++ #line == 7 ? #this_line = #1 #line == 7 ? loop_abort }
- this_line // 6th, which is the 7th line in the file
</lang>
Lua
<lang lua>iter = io.lines 'test.txt' for i=0, 5 do
if not iter() then error 'Not 7 lines in file' end
end
line = iter()</lang>
Liberty BASIC
We read the whole file into memory, and use 'word$( string, number, delimiter)'. Line delimiter is assumed to be CRLF, and the file is assumed to exist at the path given. <lang lb>fileName$ ="F:\sample.txt" requiredLine =7
open fileName$ for input as #i
f$ =input$( #i, lof( #i))
close #i
line7$ =word$( f$, 7, chr$( 13)) if line7$ =chr$( 13) +chr$( 10) or line7$ ="" then notice "Empty line! ( or file has fewer lines)."
print line7$</lang>
Mathematica
<lang Mathematica> If[# != EndOfFile , Print[#]]& @ ReadList["file", String, 7] </lang>
MATLAB / Octave
<lang Matlab>
eln = 7; % extract line number 7 line = ; fid = fopen('foobar.txt','r'); if (fid < 0)
printf('Error:could not open file\n')
else n = 0;
while ~feof(fid),
n = n + 1; if (n ~= eln), fgetl(fid); else line = fgetl(fid); end
end;
fclose(fid); end; printf('line %i: %s\n',eln,line); </lang>
Insert non-formatted text here
MoonScript
<lang MoonScript>iter = io.lines 'test.txt' for i=0, 5
error 'Not 7 lines in file' if not iter!
print iter!</lang>
NetRexx
<lang NetRexx>/* NetRexx */ options replace format comments java crossref symbols nobinary
parse arg inFileName lineNr .
if inFileName = | inFileName = '.' then inFileName = './data/input.txt' if lineNr = | lineNr = '.' then lineNr = 7
do
lineTxt = readLine(inFileName, lineNr) say '<textline number="'lineNr.right(5, 0)'">'lineTxt'</textline>'
catch ex = Exception
ex.printStackTrace()
end
return
-- ============================================================================= -- NetRexx/Java programs don't have a special mechanism to seek to a specified line number -- the simple solution is to iterate through file. (Costly for very large files) method readLine(inFileName, lineNr) public static signals IOException, FileNotFoundException
lineReader = LineNumberReader(FileReader(File(inFileName))) notFound = isTrue lineTxt = loop label reading forever line = lineReader.readLine() select when lineReader.getLineNumber() = lineNr then do lineTxt = line notFound = isFalse leave reading -- terminate I/O loop end when line = null then do leave reading -- terminate I/O loop end otherwise nop end finally lineReader.close() end reading
if notFound then signal RuntimeException('File' inFileName 'does not contain line' lineNr.right(5))
return lineTxt
-- ============================================================================= method isTrue() public static returns boolean
return 1 == 1
-- ============================================================================= method isFalse() public static returns boolean
return \(1 == 1)
</lang>
Nimrod
<lang nimrod>var
line: TaintedString f = open("test.txt", fmRead)
for x in 0 .. 6:
try: line = readLine f except EIO: echo "Not 7 lines in file"</lang>
OCaml
OCaml does not provide built-in facilities to obtain a particular line from a file. It only provides a function to read one line from a file from the current position in the input channel input_line. We can use this function to get the seventh line from a file, for example as follows:
<lang ocaml>let input_line_opt ic =
try Some (input_line ic) with End_of_file -> None
let nth_line n filename =
let ic = open_in filename in let rec aux i = match input_line_opt ic with | Some line -> if i = n then begin close_in ic; (line) end else aux (succ i) | None -> close_in ic; failwith "end of file reached" in aux 1
let () =
print_endline (nth_line 7 Sys.argv.(1))</lang>
PARI/GP
GP is not able to read specific lines, only whole files. For this capability one can use the extern
, externstr
, or system
commands together with, e.g., the AWK solution, or else use the C solution from within PARI itself.
Pascal
<lang pascal>Program FileTruncate;
uses
SysUtils;
const
filename = 'test'; position = 7;
var
myfile: text; line: string; counter: integer;
begin
if not FileExists(filename) then begin writeln('Error: File does not exist.'); exit; end;
Assign(myfile, filename); Reset(myfile); counter := 0; Repeat if eof(myfile) then begin writeln('Error: The file "', filename, '" is too short. Cannot read line ', position); Close(myfile); exit; end; inc(counter); readln(myfile); until counter = position - 1; readln(myfile, line); Close(myfile); writeln(line);
end.</lang> Output:
line 7 from file test
Perl
<lang perl>#!/usr/bin/perl -s
- invoke as <scriptname> -n=7 [input]
while (<>) { $. == $n and print, exit } die "file too short\n";</lang>
Perl 6
<lang perl6>say lines[6] // die "Short file";</lang> Without an argument, the lines function reads filenames from the command line, or defaults to standard input. It then returns a lazy list, which we subscript to get the 7th element. Assuming this code is in a program called line7:
$ cal 2011 > cal.txt $ line7 cal.txt 16 17 18 19 20 21 22 20 21 22 23 24 25 26 20 21 22 23 24 25 26 $
This works even on infinite files because lists are lazy:
$ yes | line7 y $
PicoLisp
<lang PicoLisp>(in "file.txt"
(do 6 (line)) (or (line) (quit "No 7 lines")) )</lang>
PL/I
<lang PL/I> declare text character (1000) varying, line_no fixed;
get (line_no); on endfile (f) begin;
put skip list ('the specified line does not exist'); go to next;
end;
get file (f) edit ((text do i = 1 to line_no)) (L);
put skip list (text); next: ; </lang>
PowerShell
<lang Powershell> $file = Get-Content c:\file.txt if ($file.count -lt 7) {Write-Warning "The file is too short!"} else {
$file | Where Readcount -eq 7 | set-variable -name Line7
} </lang>
Python
Using only builtins (note that enumerate
is zero-based):
<lang python>with open('xxx.txt') as f:
for i, line in enumerate(f): if i == 6: break else: print('Not 7 lines in file') line = None</lang>
Using the islice
iterator function from the itertools standard library module, which applies slicing to an iterator and thereby skips over the first six lines:
<lang python>from itertools import islice
with open('xxx.txt') as f:
try: line = next(islice(f, 6, 7)) except StopIteration: print('Not 7 lines in file')</lang>
PureBasic
<lang purebasic>Structure lineLastRead
lineRead.i line.s
EndStructure
Procedure readNthLine(file, n, *results.lineLastRead)
*results\lineRead = 0 While *results\lineRead < n And Not Eof(file) *results\line = ReadString(file) *results\lineRead + 1 Wend If *results\lineRead = n ProcedureReturn 1 EndIf
EndProcedure
Define filename.s = OpenFileRequester("Choose file to read a line from", "*.*", "All files (*.*)|*.*", 0) If filename
Define file = ReadFile(#PB_Any, filename) If file Define fileReadResults.lineLastRead, lineToRead = 7 If readNthLine(file, lineToRead, fileReadResults) MessageRequester("Results", fileReadResults\line) Else MessageRequester("Error", "There are less than " + Str(lineToRead) + " lines in file.") EndIf CloseFile(file) Else MessageRequester("Error", "Couldn't open file " + filename + ".") EndIf
EndIf </lang>
R
<lang R>> seven <- scan('hw.txt', , skip = 6, nlines = 1, sep = '\n') # too short Read 0 items > seven <- scan('Incoming/quotes.txt', , skip = 6, nlines = 1, sep = '\n') Read 1 item </lang>
Racket
<lang Racket>
- lang racket
- simple, but reads the whole file
(define s1 (list-ref (file->lines "some-file") 6))
- more efficient
- read and discard n-1 lines
(define s2
(call-with-input-file "some-file" (λ(i) (for/last ([line (in-lines i)] [n 7]) line))))
</lang>
Rebol
<lang rebol> x: pick read/lines request-file/only 7 either x [print x] [print "No seventh line"] </lang>
REXX
<lang REXX>/*REXX program to read a specific line from a file. */ parse arg fileId n . /*get the user args: fileid n */ if fileID== then fileId='JUNK.TXT' /*assume fileID default: JUNK.TXT*/ if n== then n=7 /*assume N default: 7 */ L=lines(fileid) /*first, see if the file exists. */ if L==0 then do; say 'error, fileID not found:' fileId; exit; end q=linein(fileId, n) /*read the Nth line, store in Q.*/ if length(q)==0 then say 'line' n "not found."
else say 'file' fileId "record" n '=' q /*stick a fork in it, we're done.*/</lang>
Ruby
The each_line method returns an Enumerator, so no more than seven lines are read. <lang ruby> seventh_line = open("/etc/passwd").each_line.take(7).last </lang>
Run BASIC
<lang runbasic>fileName$ = "f:\sample.txt" requiredLine = 7 open fileName$ for input as #f
for i = 1 to requiredLine
if not(eof(#f)) then line input #f, a$
next i close #f print a$ end</lang>
Scala
The code will throw a NoSuchElementException if the file doesn't have 7 lines.
<lang scala>val lines = io.Source.fromFile("input.txt").getLines val seventhLine = lines drop(6) next</lang>
Solving the task to the letter, imperative version:
<lang scala>var lines: Iterator[String] = _ try {
lines = io.Source.fromFile("input.txt").getLines drop(6)
} catch {
case exc: java.io.IOException => println("File not found")
} var seventhLine: String = _ if (lines != null) {
if (lines.isEmpty) println("too few lines in file") else seventhLine = lines next
} if ("" == seventhLine) println("line is empty")</lang>
Functional version:
<lang scala>val file = try Left(io.Source.fromFile("input.txt")) catch {
case exc => Right(exc.getMessage)
} val seventhLine = (for(f <- file.left;
line <- f.getLines.toStream.drop(6).headOption.toLeft("too few lines").left) yield if (line == "") Right("line is empty") else Left(line)).joinLeft</lang>
sed
To print seventh line <lang sed> sed -n 7p </lang> To print error message if no such line <lang sed> sed -n '7{p;h;}; ${x;/^$/s/^/Error: no such line/p}' </lang> That is we remember (h) the line, if any, in hold space. At last line ($) we exchange (x) pattern space and hold space. If hold space was empty -- print error message.
Seed7
The function getLine skips lines with readln and reads the requested line with getln afterwards:
<lang seed7>$ include "seed7_05.s7i";
const func string: getLine (inout file: aFile, in var integer: lineNum) is func
result var string: line is ""; begin while lineNum > 1 and hasNext(aFile) do readln(aFile); decr(lineNum); end while; line := getln(aFile); end func;
const proc: main is func
local var string: fileName is "input.txt"; var file: aFile is STD_NULL; var string: line is ""; begin aFile := open(fileName, "r"); if aFile = STD_NULL then writeln("Cannot open " <& fileName); else line := getLine(aFile, 7); if eof(aFile) then writeln("The file does not have 7 lines"); else writeln("The 7th line of the file is:"); writeln(line); end if; end if; end func;</lang>
Sidef
<lang ruby>func getNthLine(filename, n) {
var file = File.new(filename); file.open_r.each { |line| $. == n && return line; }; Sys.warn("file #{file} does not have #{n} lines, only #{$.}\n"); return nil;
}
var wantedLine = getNthLine("/etc/passwd", 7); wantedLine != nil && print wantedLine;</lang>
Smalltalk
<lang smalltalk> line := (StandardFileStream oldFileNamed: 'test.txt') contents lineNumber: 7. </lang>
Tcl
This code can deal with very large files with very long lines (up to 1 billion characters in a line should work fine, provided enough memory is available) and will return an empty string when the nth line is empty (as an empty line is still a valid line). <lang tcl>proc getNthLineFromFile {filename n} {
set f [open $filename] while {[incr n -1] > 0} { if {[gets $f line] < 0} { close $f error "no such line" } } close $f return $line
}
puts [getNthLineFromFile example.txt 7]</lang>
Where it is necessary to provide very fast access to lines of text, it becomes sensible to create an index file describing the locations of the starts of lines so that the reader code can seek
directly to the right location. This is rarely needed, but can occasionally be helpful.
TorqueScript
%file = new fileObject(); %file.openForRead("File/Path.txt"); $seventhLine = ""; while(!%file.isEOF()) { %line++; if(%line == 7) { $seventhLine = %file.readLine(); if($seventhLine $= "") { error("Line 7 of the file is blank!"); } } } %file.close(); %file.delete(); if(%line < 7) { error("The file does not have seven lines!"); }
TUSCRIPT
<lang tuscript>$$ MODE TUSCRIPT file="lines.txt" ERROR/STOP OPEN (file,READ,-std-) line2fetch=7</lang>
TXR
From the top
Variable "line" matches and takes eighth line of input: <lang txr>@(skip nil 7) @line</lang>
From the bottom
Take the third line from the bottom of the file, if it exists.
<lang txr>@(skip)
@line
@(skip 1 2)
@(eof)</lang>
How this works is that the first skip
will skip enough lines until the rest of the query successfully matches the input. The rest of the query matches a line, then skips two lines, and matches on EOF. So @line
can only match at one location: three lines up from the end of the file. If the file doesn't have at least three lines, the query fails.
UNIX Shell
<lang bash>get_nth_line() {
local file=$1 n=$2 line while ((n-- > 0)); do if ! IFS= read -r line; then echo "No such line $2 in $file" return 1 fi done < "$file" echo "$line"
}
get_nth_line filename 7</lang>
Vedit macro language
This example reads the 7th line (including newline character(s)) into text register 10.
<lang vedit>File_Open("example.txt", BROWSE) Goto_Line(7) if (Cur_Line < 7) {
Statline_Message("File contains too few lines")
} else {
if (At_EOL) { Statline_Message("Empty line") } Reg_Copy(10, 1)
} Buf_Close(NOMSG) </lang>
If the file does not exist, the buffer will be empty and you get "File contains too few lines" error.
If the line is too long (more than about 230,000 characters), Vedit displays error message "Block too large for text registers, try clipboard"). This error could be avoided by reading the line to clipboard (which has larger size limit) or by copying the line to another edit buffer using a tmp file (in which case there is no size limit).
XPL0
Filename.ext must be terminated with an EOF character (hex 1A). Usage: readline <filename.ext
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations def MaxLen = 82; \maximum length of line that can be stored (incl CR+LF)
func ReadLine(N, L); \Read line N from input file and return it in string L int N; char L; int I, C; [for I:= 1 to N-1 do \skip to start of specified line
repeat C:= ChIn(1); if C = $1A\EOF\ then [Text(0, "File only has "); IntOut(0, I); Text(0, " lines^M^J"); return false]; until C = $0A\LF\;
I:= 0; repeat C:= ChIn(1);
if C = $1A\EOF\ then [Text(0, "Line is empty (EOF)^M^L"); return false]; L(I):= C; I:= I+1;
until C=$0A\LF\ or I>=MaxLen; if I >= MaxLen then Text(0, "Line might be truncated^M^J"); if I = 2 then Text(0, "Line is empty^M^J"); L(I-1):= L(I-1) ! $80; \terminate string return true; ];
char LineN(MaxLen); if ReadLine(7, LineN) then Text(0, LineN)</lang>
zkl
Many zkl sequence objects contain a readln method, some contain a seek (or equivalent) method. However, File only has readln. If, for some, reason, the nth line can't be read, an exception is thrown. <lang zkl>reg line; do(7){line=File.stdin.readln()} println(">>>",line);</lang> Or, suck in lines and take the last one: <lang zkl>lines:=File.stdin.readln(7); println(">>>",line[-1]);</lang>
- Programming Tasks
- Solutions by Programming Task
- Ada
- Aime
- ALGOL 68
- AutoHotkey
- AWK
- BBC BASIC
- C
- C++
- Clojure
- Common Lisp
- C sharp
- D
- Erlang
- F Sharp
- Go
- Groovy
- Haskell
- Icon
- Unicon
- J
- Java
- Julia
- Lasso
- Lua
- Liberty BASIC
- Mathematica
- MATLAB
- Octave
- MoonScript
- NetRexx
- Nimrod
- OCaml
- PARI/GP
- Pascal
- Perl
- Perl 6
- PicoLisp
- PL/I
- PowerShell
- Python
- PureBasic
- R
- Racket
- Rebol
- REXX
- Ruby
- Run BASIC
- Scala
- Sed
- Seed7
- Sidef
- Smalltalk
- Tcl
- TorqueScript
- TUSCRIPT
- TXR
- UNIX Shell
- Vedit macro language
- XPL0
- Zkl
- File handling