いくつかの実験の後、私は の独自の実装を書くことができましたg_input_stream_read
。あまりきれいではなく、安全ではないかもしれませんが、これにより、メインの上部で指定されたファイルの最初の 1,024 文字が正常に出力されます。
import Control.Monad (liftM)
import Data.Char (chr)
import Data.Word (Word8)
import Foreign
import Foreign.C (CInt)
import System.GIO
import System.GIO.Types (unInputStream, toInputStream)
import System.Glib (glibTypeInit, GError)
foreign import ccall unsafe "g_input_stream_read"
-- inputStreamRead <stream> <buffer> <count> <cancellable> <error>, returns the number of bytes read
inputStreamRead :: Ptr InputStream -> Ptr a -> CInt -> Ptr (Maybe Cancellable) -> Ptr GError -> IO (CInt)
addrToChar :: Ptr a -> Int -> IO (Char)
addrToChar p i = do
let addr = p `plusPtr` i
val <- peek addr :: IO Word8
return $ chr (fromIntegral val)
main :: IO ()
main = do
glibTypeInit
let file = fileFromParseName "file.txt"
fileInputStream <- fileRead file Nothing
let stream = unInputStream $ toInputStream fileInputStream
allocaBytes 1024 $ \buffer -> do
alloca $ \err -> do
bytesRead <- liftM fromEnum $ inputStreamRead (unsafeForeignPtrToPtr stream) buffer 1024 nullPtr err :: IO Int
result <- mapM (addrToChar buffer) [0..bytesRead]
putStrLn result
シンプルな にするためには多少の作業が必要inputStreamRead :: InputStream -> IO (String)
ですが、少なくとも正しい方向への一歩です。
編集:より良い解決策を見つけました。これは、読み取ったバイト数が 0 になるまで読み取り続ける必要があり、より使いやすいエントリ ポイントがあります。
import Control.Monad (liftM)
import Data.Char (chr)
import Data.Word (Word8)
import Foreign
import Foreign.C (CInt)
import System.GIO
import System.GIO.Types
import System.Glib (glibTypeInit, GError)
foreign import ccall unsafe "g_input_stream_read"
-- inputStreamRead <stream> <buffer> <count> <cancellable> <error>, returns the number of bytes read
inputStreamRead :: Ptr InputStream -> Ptr a -> CInt -> Ptr Cancellable -> Ptr GError -> IO (CInt)
chunk :: Int
chunk = 4096
bytesToText :: [Word8] -> [Char]
bytesToText [] = []
bytesToText (x:xs) = (chr $ fromEnum x):(bytesToText xs)
readGIOStream :: InputStream -> Maybe Cancellable -> IO ([Word8])
readGIOStream stream cancel = do
allocaBytes chunk $ \buffer -> do
alloca $ \err -> do
case cancel of
Just c -> withForeignPtr (unCancellable c) $ \c' -> readChunk buffer c' err streamPtr
Nothing -> readChunk buffer nullPtr err streamPtr
where streamPtr = unInputStream stream
readChunk b c e s = withForeignPtr s $ \s' -> do
bytesRead <- liftM fromEnum $ inputStreamRead s' b (toEnum chunk) c e
result <- mapM (\i -> peek $ b `plusPtr` i) [0..(bytesRead-1)]
if bytesRead == 0
then return result
else do rest <- readChunk b c e s
return $ result ++ rest
main :: IO ()
main = do
glibTypeInit
let file = fileFromParseName "live-forever.txt"
fileInputStream <- fileRead file Nothing
text <- liftM bytesToText $ readGIOStream (toInputStream fileInputStream) Nothing
putStrLn text