Instant readFile

Simon Marlow
Thu, 16 Nov 2000 02:24:36 -0800

George Russell writes:
> The 
>    readFile :: FilePath -> IO String
> action returns the contents of the associated file.  This is 
> almost what
> I want, but not quite, because readFile is lazy.  Hence if 
> the string is
> only partly read, the file is still open.  What I want 
> instead is a function
> which
>    (a) opens the file;
>    (b) slurps the complete contents compactly into an array;
>    (c) closes the file;
>    (d) makes the contents of the array available as a String.
> So instead I wrote the following:
> copyFileToString  :: FilePath -> IO String
> copyFileToString file =
>    do
>       (addr,len) <- IOExts.slurpFile file
>       CString.unpackCStringLenIO addr len
> However on further consideration this also seems to me to be 
> unsatisfactory, 
> because although I don't understand this issue very well, I 
> don't think
> the (addr) address containing the complete file contents will ever get
> deallocated, because there's no way the GC can know that this 
> particular
> Addr can be free'd.  (Is that correct?)  So please, how 
> _should_ I write this
> function?

Well, you could always free the address directly after unpacking it,
since unpackCStringLenIO generates the whole string in one go.

> It all is a bit of a mystery to me how you are supposed to 
> use Addr like things
> without space leaks.  A little more explanation in the 
> documentation would not
> perhaps be amiss . . .

The alternative is to use a ByteArray to store the string.  These live
in the heap and so get garbage collected automatically, and should be
quicker to allocate than using malloc.

Check out the hGetBuf family of functions in IOExts, there are versions
for reading into/out of ByteArrays, and there are variants of
unpackCString that work with ByteArrays (unpackNBytesBA, for example).

[ side note: ByteArrays and MutableByteArrays will eventually be
replaced by UArray and STUArray/IOUArray which are functionally
identical but have a nice overloaded interface in IArray/MArray. ]