rewritten the IO functions to avoid multiple passes