How do I read a file line by line in EK9?
← File I/O · Ref: Q154
EK9 treats file input as a stream source. Open a file with TextFile.input() inside a try block, then use cat to pipe lines through stream operations like filter, map, and collect.
STREAMING FILE INPUT
Open the file and stream its contents:
file <- TextFile(FileSystemPath().inCurrentWorkingDirectory("data.txt")) try -> input <- file.input() if input? cat input > stdout
Each line from the file flows through the pipeline as a String. A TextFile of a missing path (or a relative one: TextFile("data.txt") is never resolved against the working directory) is unset and so is its input(); the try body still runs, which is why it checks input? first.
MAKING SURE THE FILE EXISTS
FileSystemPath.createFileIfAbsent() creates an empty file when needed and returns a Result that must be checked:
path <- FileSystemPath("data.txt") created <- path.createFileIfAbsent()
CAT WITH FILE INPUT
The cat operation treats the input stream as a source of lines:
cat input | map with processLine > stdout
This sends each line through the processLine function before printing.
FILTER AND TRANSFORM LINES
Combine file streaming with pipeline operations:
cat input | filter by notEmpty | map with trimmed > stdout
This skips empty lines and trims whitespace from each remaining line. Both stages need functions: notEmpty must test 'line is not empty', because an empty line "" is SET and 'line?' would let it through; trimmed wraps the String method trim(), which cannot be named in 'map with' directly:
notEmpty() as pure -> line as String <- rtn as Boolean: line is not empty trimmed() as pure -> line as String <- rtn as String: line.trim()
COLLECT LINES INTO LIST
Gather all lines into a collection:
allLines <- cat input | collect as List of String
This reads every line and stores them in a List for further processing.
See Q89 for stream pipelines. See Q151 for reading files. See Q125 for head/tail/skip.
Example
defines module qa.fileio.lines defines function notEmpty() as pure -> line as String <- rtn as Boolean: line is not empty trimmed() as pure -> line as String <- rtn as String: line.trim() addLineNumber() as pure -> line as String <- rtn as String: ">> " + line defines program ReadFileLinesDemo() stdout <- Stdout() // === TEXTFILE FOR LINE READING === // createFileIfAbsent returns a Result that must be checked path <- FileSystemPath("/tmp/qa-example-lines.txt") created <- path.createFileIfAbsent() stdout.println(`File ready: ${created.isOk()}`) file <- TextFile(path) stdout.println("File for line reading: " + $file) // Three lines, the middle one empty try -> output <- file.output() if output? output.println("line one") output.println("") output.println(" line three ") // === FILTER AND TRANSFORM === // An empty line "" is SET, so notEmpty tests 'is not empty', not '?' try -> input <- file.input() if input? cat input | filter by notEmpty | map with trimmed | map with addLineNumber > stdout // === COLLECT INTO LIST === try -> input <- file.input() if input? allLines <- cat input | collect as List of String stdout.println(`Lines collected: ${length allLines}`) stdout.println("Line-by-line processing uses cat with file input streams")
Common mistakes
E50060 — TextFile has no toString() method. Use the $ prefix operator for string conversion. See ek9 -h E50060 for details.
Incorrect:
stdout.println(file.toString())
Correct:
stdout.println("File for line reading: " + $file)
E50060 — TextFile has no readLines() method. Use file.input() inside a try block to get a stream for line-by-line processing. See ek9 -h E50060 for details.
Incorrect:
stdout.println(file.readLines())
Correct:
stdout.println("Line-by-line processing uses cat with file input streams")
Other ways to ask this
- How do I process a file line by line in EK9?
- How do I stream file contents in EK9?
- How do I use cat with file input in EK9?
Coming from another language?
Java: Files.lines(Path) returns a Stream of String for lazy line-by-line processing. Python: for line in open('file') iterates lazily. Rust: BufRead::lines() returns an iterator of lines. Go: bufio.Scanner for line-by-line reading. EK9: cat input with TextFile.input() in a stream pipeline, supporting filter, map, collect and all stream operations.
Keywords: lines, filter, read, cat, line, pipeline, write, file, stream, iterate