I wouldn’t open and close the file. Open the file once, use seek()
to jump around to different locations in the file and read/write the data you need to.
If you are using threads then you need to synchronize access to the file, i.e. if thread 1 seeks to offset 1000 then writes 1k, and thread 2 at the same time seeks to offset 5000 to read 1k. The last seek “wins” so that is the offset you will at for both operations.
The two ways to protect this would either be using a ReentrantLock to protect all reads and writes something like:
function myread(file, protect, offset, bytes)
lock(protect)
seek(file, offset)
data = read(file, bytes)
unlock(protect)
return data
end
function mywrite(file, protect, offset, data)
lock(protect)
seek(file, offset)
write(file, data)
unlock(protect)
end
Another option might be to use a task:
filechan = Channel{Func}(100)
@async begin
global filechan
file = open("foo.dat", "w+")
for f in filechan
f(file)
end
close(file)
end
fileop(f) = put!(filechan, f)
# Then to do file operations would be:
fileop() do f
seek(1000)
read(f, 100)
end
The channel will ensure that all the file operations are serialized. While I kind of like this way of protecting file access you might run into trouble. Julia can get funny when a task tries to call functions created AFTER the task is started…so you might need to change f(file)
to invokelatest(f, file)
if you get “running in world age X, while current world is Y" errors.
One caveat here is I wrote this code without testing, so I can’t promise it to be error free. I seem to remember a maxim about all code can be reduce by 1 line and contains at least 1 error.