8. File Contents

Introduction

datafile.each(s ->
    s.chomp!
    s.size.println                      # output size of line
)

lines = datafile.lines
whole_file = file.whole

["One", "two", "three" ].each(print(handle,))  # "Onetwothree"
println("Baa baa black sheep.")         # Sent to default output handle

buffer = handle.read(4096)

handle.truncate(length)
"tmp/{Sys::pid}.pid".truncate(length)

pos = datafile.tell_seek
println("I'm {pos} bytes from the start of DATAFILE.")

logfile.seek!(End)
datafile.seek!(0)
out.seek!(out.tell_seek - 20)

datafile = datafile.print(mystring)
block = infile.read(256)                # can't do offset writing of 5

Reading Lines with Continuation Characters


while not fh.empty? do
    lines = fh.take_while(substr!?(, "\\$", ""))
    line = lines.join("")
    # process full record in {line} here

Counting Lines (or Paragraphs or Records) in a File


file.open.lines.size

f = file.open(Sep_keep("\n+"))         # enable paragraph mode for "line", "lines", "each"...
f.lines.size

Processing Every Word in a File

Sys::stdall.each(s ->
    s.words.each(word ->
        # do something with {word}
    )
)

Sys::stdall.reopen(Sep("\s+")).each(s ->
    # do something with {word}
)

# Make a word frequency count
seen = {}
Sys::stdall.reopen(Sep("\s+")).each(s -> seen{s.downcase}++)
# output hash in a descending numeric sort of its values
seen.keys.sort_by(a,b -> seen{b} <=> seen{a})
    .iter(word -> "%5d %s\n".printf(seen{word}, word))

# Line frequency count
seen = {}
Sys::stdall.each(s -> seen{s.downcase}++)
# output hash in a descending numeric sort of its values
seen.keys.sort_by(a,b -> seen{b} <=> seen{a})
    .iter(line -> "%5d %s".printf(seen{line}, line))

Reading a File Backwards by Line or Paragraph

file.lines.reverse.each(line ->
    # do something with {line}
)

file.open(Sep_keep("\n+")).lines.reverse.each(paragraph ->
    # do something with paragraph    
)

Trailing a Growing File

loop
    fh.each(line ->
        # ...
    )
    sleep(sometime)
    # clearerr?

Picking a Random Line from a File

i = 0
line = stdall.find(_ -> i++ ; random(i) == 0)
# {line} is the random line

i = 0
adage = "/usr/share/games/fortunes"
    .open(Sep("%\n"))
    .find(_ -> i++ ; random(i) == 0)
adage.print 

Randomizing All Lines

input.lines.randomize.each(s -> output.print(s))

Reading a Particular Line in a File

i = 0
line = handle.find(_ -> i++ ; i == desired_line_number)

line = handle.to_list[desired_line_number]


build_index(data_file, index_file) =
    offset = 0
    in.each(_ ->
        out.print(offset.pack("N"))
        offset = in.tell_seek
    )
    
line_with_index(data_file, index_file, line_number) =
    i_offset = line_number-1 * pack_size("N")
    index_file.seek!(i_offset) or return
    
    entry = index_file.read(pack_size("N"))
    d_offset = entry.unpack("N")
    data_file.seek!(d_offset)
    data_file.line

# usage:
in = file.open
index = "{file}.idx".open(R | W)
build_index(in, index)
line = line_with_index(in, index, seeking)

Processing Variable-Length Text Fields

"3+5-2".split("([+-])")                 #=> [ "3", "+", "5", "-", "2" ]
fields = record.split(":")
fields = record.split("\s+")
fields = record.words

Removing the Last Line of a File

fh = file.open(R | W)
addr = 0
fh.each(_ -> addr = fh.tell_seek if not file.empty?)
fh.truncate!(addr)

Processing Binary Files

# don't care about non-UNIX ;pp

Using Random-Access I/O

address = recsize * recno
fh.seek!(address)
buffer = fh.read(recsize)

Updating a Random-Access File

address = recno * pack_size(format)
fh.seek!(address)
fields = fh.read_unpack(format)
# update fields, then
fh.seek!(address)
fields.pack_print(format, fh)

# weekearly -- set someone's login date back a week
user    = Sys::args[0] or Sys::env{"USER"} or Sys::env{"LOGNAME"}

typedef = "L A12 A16"                   # linux fmt; sunos is "L A8 A16"
address = Sys::getpwnam(user){Uid} * pack_size(typedef)

lastlog = "/var/log/lastlog".open(R | W)
    or die("can't update /usr/adm/lastlog: {Sys::errno_string}")
lastlog.seek!(address)

(time, line, host) = lastlog.read_unpack(typedef)
time -= 24 * 7 * 60 * 60                # back-date a week

lastlog.seek!(address)
(time, line, host).pack_print(typedef, lastlog)

Reading a String from a Binary File

file : addrs = Sys::args
if addrs == [] then die("usage: {Sys::progname} addr ...\n")
        
fh = file.open(Sep("\0"))
addrs.each(s ->
    fh.seek!(s.to_int)
    qq(%#x %#o %d "%s"\n).printf(addr, addr, addr, fh.line)  
)

Reading Fixed-Length Records

while not file.empty? do
    fields = file.read_unpack(template)
    # use fields

Reading Configuration Files

config.each(s ->
    s.chomp!                            # no newline
    s.subst!("#.*", "")                 # no comments
    s.chop_bounding_spaces!             # no leading white, no trailing white
    s.m!(
        "(\S*)\s*=\s*(.*)", 
        var, value -> User_Preferences{var} = value
    )
)

Testing a File for Trustworthiness

info = File::stat(filename)
println("Superuser owns filename") if info{Uid} == 0
println("filename has been read since it was written.") if info{Atime} > info{Mtime}

Program: tailwtmp

Program: tctee

Program: laston