Rework file IO, separate threaded functions

Separating threaded and non-threaded functions creates some code
redundancy but it eliminates a bunch of conditionals and makes things a
bit clearer I think.