0

たとえば、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 では実装されていないようです。

何か不足していますか?

4

1 に答える 1

1

いくつかの実験の後、私は の独自の実装を書くことができました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
于 2012-10-17T18:40:33.390 に答える