例如,这是我使用Haskell和gtk2hs编写的一小段程序:
import System.GIO
foreign import ccall safe "g_type_init"
g_type_init :: IO ()
main :: IO ()
main = do
g_type_init
let file = fileFromParseName "my-file.txt"
inputStream <- fileRead file Nothing
...fileRead方法返回一个FileInputStream实例,但是我在文档的任何地方都找不到可以从中读取的方法。在GIO中对应的C方法应该是g_input_stream_read,但它似乎没有在gtk2hs中实现。
我是不是遗漏了什么?
发布于 2012-10-18 02:40:33
经过一些实验之后,我设法编写了自己的g_input_stream_read实现。它不是很漂亮,甚至可能不安全,但这将成功打印在main的顶部指定的文件的前1024个字符:
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 texthttps://stackoverflow.com/questions/12924996
复制相似问题