I want something that looks like a file handle but is really backed by an in-memory buffer to use for I/O redirects. How can I do this?
How do I create an in-memory handle in Haskell?
This is actually a bug in the library design, and one that's annoyed me, too. I see two approaches to doing what you want, neither of which is terribly attractive.
Create a new typeclass, make the current handle an instance of it, write another instance to do the in-memory-data thing, and change all of your programs that need to use this facility. Possibly this is as simple as importing
System.SIO(or whatever you want to call it) instead of
System.IO. But if you use the custom I/O routines in libraries such as
Data.ByteString, there's more work to be done there.
Rewrite the I/O libraries to extend them to support this. Not trivial, and a lot of work, but it wouldn't be particularly difficult work to do. However, then you've got a compatibility issue with systems that don't have this library.
This may not be possible. GHC, at least, seems to require a handle to have an OS file descriptor that is used for all read/write/seek operations.
/libraries/base/IOBase.lhs from the GHC sources.
You may be able to get the same effect by enlisting the OS's help: create a temporary file, connect the handle to it and then memory map the file for the I/O redirects. This way, all the handle I/O would become visible in the memory mapped section.
I just wrote a library which provides this, called "knob" [hackage]. You can use it to create
Handles which reference/modify a
import Data.ByteString (pack) import Data.Knob import System.IO main = do knob <- newKnob (pack ) h <- newFileHandle knob "test.txt" WriteMode hPutStrLn h "Hello world!" hClose h bytes <- Data.Knob.getContents knob putStrLn ("Wrote bytes: " ++ show bytes)