Write to a particular line in a file

Is there a native Julia command to write to a particular line of a file? I know how to open a file, namely using open, but it seems like the options are to overwrite the entire file (with the “w” and write commands/options), or write to its end (with the “a” and write commands/options). I haven’t found an option to specify a line to add content to.

I know that if all else fails, I could use:

run(`sed -i "$line i What I want to write" $file`)

But I’m wondering whether there’s another way that just uses Julia commands and no external commands.

2 Likes

Here is one way to do this:

julia> function skiplines(io::IO, n)
           i = 1
           while i <= n
              eof(io) && error("File contains less than $n lines")
              i += read(io, Char) === '\n'
           end
       end
skiplines (generic function with 1 method)

julia> # write 3 lines to test.foo
       write("test.foo", "foo\nbar\nbaz\n")
12

julia> f = open("test.foo", "r+")
IOStream(<file test.foo>)

julia> skiplines(f, 2)

julia> # seek stream back before the last '\n'
       skip(f, -1)
IOStream(<file test.foo>)

julia> # mark current stream position, so we can seek back later
       mark(f)
7

julia> buf = IOBuffer()
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=0, maxsize=Inf, ptr=1, mark=-1)

julia> # write rest of file into buf
       write(buf, f)
5

julia> seekstart(buf)
IOBuffer(data=UInt8[...], readable=true, writable=true, seekable=true, append=false, size=5, maxsize=Inf, ptr=1, mark=-1)

julia> # go back to the end of the 2nd line we marked earlier
       reset(f)
7

julia> print(f, "bara")

julia> # now write rest of file from buf back into f
       write(f, buf)
5

julia> close(f)

julia> Text(read("test.foo", String))
foo
barbara
baz
4 Likes

I tried copy-pasting your code into a function, editL. Here it is:

function editL(file, string, no)
    write(file, string);
    f = open(file, "r+");
    skiplines(f, no);
    skip(f, -1)
    mark(f)
    buf = IOBuffer()
    write(buf, f)
    seekstart(buf)
    reset(f)
    write(f, buf)
    close(f)
end

and it doesn’t do what I expected, it actually deletes the whole file and adds string (the contents of that third argument, not the word string) to it.

Delete the first line. The first write is just to create the file test.foo for this demonstration.

Turns out your code also solves Writing LaTeX from Julia.