FILES

Programs forget everything when they end, unless they write it down. Satellite’s files are built on one simple idea: a text file is a list of lines that lives on the disk. Line 1 is the first line, each line is a string, and most of what you can do to a list you can do to a file, spelled the same way.

A file is held in a satellite.variable.file. You get one from satellite.file.new or satellite.file.open, and after that you work through its name.

Making a file and reading it back

  • satellite.file.new("name.txt") makes a new, empty text file and opens it. It never replaces a file that is already there.
  • f.append("text") adds a line at the end.
  • f[n] reads line n, counting from 1. f.first and f.last read the first and last lines, and f.size says how many lines there are.
  • f.close() saves and closes the file, and answers true when the changes reached the disk.
shopping.satlSATELLITE 004 Download
Write three lines, then read them back
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file shopping = satellite.file.new("shopping.txt")
    shopping.append("bread")
    shopping.append("milk")
    shopping.append("eggs")
    satellite.console.display(shopping.size)
    satellite.console.display(shopping[1])
    satellite.console.display(shopping.last)
    satellite.console.display(shopping.close())
    satellite.return(satellite)
}
OUTPUT
3
bread
eggs
true

After this runs, shopping.txt sits beside the program with bread, milk and eggs on three lines. A path without a / at the front is found in the folder of the .satl file that uses it, wherever you ran satl from.

Opening a file and changing it

satellite.file.open("name.txt") opens a text file that is already there. These change its lines:

  • f.insert(n, "text") puts a new line in as line n, and everything from there down moves down one.
  • f.replace(n, "text") makes line n say something else.
  • f.replace("old", "new") changes the first place old appears in the file into new. A number first means a line, and text first means text.
  • f.remove_at(n), f.remove("a line"), f.remove_first(), f.remove_last(), f.truncate(n) and f.clear() take lines out.

And these find things without changing anything:

  • f.index_of("a line") answers the number of the first line that is exactly that text, and f.search("text") the first line that contains it anywhere. When nothing matches, both answer 0, which is never a line.
  • f.contains("a line") answers true or false.
  • f.read_all answers the whole file as one string, line endings included.

To walk every line, count from 1 up to f.size:

shopping_edit.satlSATELLITE 004 Download
Make a file, open it again, change it and walk it
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file shopping = satellite.file.new("shopping.txt")
    shopping.append("bread")
    shopping.append("milk")
    shopping.append("eggs")
    shopping.close()

    satellite.variable.file again = satellite.file.open("shopping.txt")
    again.insert(2, "butter")
    again.replace(1, "brown bread")
    again.replace("milk", "oat milk")
    satellite.console.display(again.search("milk"))
    satellite.console.display(again.index_of("cheese"))
    satellite.console.display(again.contains("butter"))
    satellite.statement.for(satellite.variable.number i = 1; i <= again.size; i + 1)
    {
        satellite.console.display(i.to_string() + ". " + again[i])
    }
    satellite.return(satellite)
}
OUTPUT
3
0
true
1. brown bread
2. butter
3. oat milk
4. eggs

Notice there is no again.close() at the end. Satellite saves and closes every file that is still open when the program ends, so forgetting to close loses nothing. You can also save part way through with f.save().

A save is whole or not at all. Satellite writes the new version beside the old one and swaps it in, so if the program is stopped in the middle of a save, the file holds either the old lines or the new ones, never a mixture.

When a file will not open

Opening or making a file never stops your program. Instead, the file you get back is not open, and you can ask it:

  • f.ok answers whether it is open.
  • f.error says why not, in words.
  • satellite.file.exists("name.txt") answers whether a file is there at all.
careful_opening.satlSATELLITE 004 Download
open never makes a file, and new never replaces one
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file missing = satellite.file.open("no_such_file.txt")
    satellite.console.display(missing.ok)
    satellite.console.display(satellite.file.exists("no_such_file.txt"))

    satellite.variable.file diary = satellite.file.new("diary.txt")
    diary.append("day one")
    diary.close()
    satellite.variable.file second = satellite.file.new("diary.txt")
    satellite.console.display(second.ok)

    satellite.variable.file reopened = satellite.file.open("diary.txt")
    satellite.console.display(reopened[1])
    satellite.return(satellite)
}
OUTPUT
false
false
false
day one

open never makes a file, so a misspelled name cannot quietly become an empty one. new never replaces one, so your diary survives: the second new came back not open, and the first day is still there.

What is refused

A few things stop the program, because any answer to them would be made up:

  • Reading a line that is not there, like line 2 of a one-line file, is S501 LINE_PAST_THE_END.
  • Asking about the lines of a file that is not open, like missing.size, is S503 FILE_NOT_OPEN. Check f.ok first.
  • A method a file does not have, such as f.write("text"), or the wrong number of arguments, such as f.replace(1), is refused before the program starts. To add a line, use append or insert.
past_the_end.satlSATELLITE 004 Download
Line 2 of a one-line file
satellite.include(satellite)

satellite.capsule satellite.main()
{
    satellite.variable.file notes = satellite.file.new("notes.txt")
    notes.append("the only line")
    satellite.console.display(notes[1])
    satellite.console.display(notes[2])
    satellite.return(satellite)
}
OUTPUT
--------------------------------------------------------------------------------
SATELLITE CRITICAL ERROR REPORT
--------------------------------------------------------------------------------
S501: LINE_PAST_THE_END
satl(run): notes[2]: there is no such line -- the file has 1 line, counting from
1

directory: past_the_end.satl:8
syntax: satellite.console.display(notes[2])
        /\

a line was read by its number and the file has no line with that number. Lines
count from 1, and the last one is the file's size.
machine code 47 line_past_the_end -- satl exits with this.

--------------------------------------------------------------------------------

The first line was shown before the report. The file itself is safe: notes.txt was still saved with its one line.

Only text files are built today. Asking for a binary file, satellite.file.new("data.bin", "binary"), gives a file that is not open.

Where next

Every file word is in the FULL REFERENCE. Files behave like LISTS, and two threads can share one safely with a lock: see LOCKS: SHARING AN OBJECT BETWEEN THREADS.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *