1{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
3-- Module : Data.Text.IO
4-- Copyright : (c) 2009, 2010 Bryan O'Sullivan,
5-- (c) 2009 Simon Marlow
7-- Maintainer : bos@serpentine.com
8-- Stability : experimental
11-- Efficient locale-sensitive support for text I\/O.
13-- Skip past the synopsis for some important notes on performance and
14-- portability across different versions of GHC.
23 -- * File-at-a-time operations
27 -- * Operations on handles
32 -- * Special cases for standard input and output
40import Data.Text (Text)
41import Prelude hiding (appendFile, catch, getContents, getLine, interact,
42 putStr, putStrLn, readFile, writeFile)
43import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
45#if __GLASGOW_HASKELL__ <= 610
46import qualified Data.ByteString.Char8 as B
47import Data.Text.Encoding (decodeUtf8, encodeUtf8)
49import Control.Exception (catch, throwIO)
50import Control.Monad (liftM2, when)
51import Data.IORef (readIORef, writeIORef)
52import qualified Data.Text as T
53import Data.Text.Fusion (stream)
54import Data.Text.Fusion.Internal (Step(..), Stream(..))
55import Data.Text.IO.Internal (hGetLineWith, readChunk)
56import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
57 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
59import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
60import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
62import GHC.IO.Handle.Text (commitBuffer')
63import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
64 HandleType(..), Newline(..))
65import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)
66import System.IO.Error (isEOFError)
72-- The functions in this module obey the runtime system's locale,
73-- character set encoding, and line ending conversion settings.
75-- If you know in advance that you will be working with data that has
76-- a specific encoding (e.g. UTF-8), and your application is highly
77-- performance sensitive, you may find that it is faster to perform
78-- I\/O with bytestrings and to encode and decode yourself than to use
79-- the functions in this module.
81-- Whether this will hold depends on the version of GHC you are using,
82-- the platform you are working on, the data you are working with, and
83-- the encodings you are using, so be sure to test for yourself.
85-- | The 'readFile' function reads a file and returns the contents of
86-- the file as a string. The entire file is read strictly, as with
88readFile :: FilePath -> IO Text
89readFile name = openFile name ReadMode >>= hGetContents
91-- | Write a string to a file. The file is truncated to zero length
92-- before writing begins.
93writeFile :: FilePath -> Text -> IO ()
94writeFile p = withFile p WriteMode . flip hPutStr
96-- | Write a string the end of a file.
97appendFile :: FilePath -> Text -> IO ()
98appendFile p = withFile p AppendMode . flip hPutStr
100-- | Read the remaining contents of a 'Handle' as a string. The
101-- 'Handle' is closed once the contents have been read, or if an
102-- exception is thrown.
104-- Internally, this function reads a chunk at a time from the
105-- lower-level buffering abstraction, and concatenates the chunks into
106-- a single string once the entire file has been read.
108-- As a result, it requires approximately twice as much memory as its
109-- result to construct its result. For files more than a half of
110-- available RAM in size, this may result in memory exhaustion.
111hGetContents :: Handle -> IO Text
112#if __GLASGOW_HASKELL__ <= 610
113hGetContents = fmap decodeUtf8 . B.hGetContents
116 chooseGoodBuffering h
117 wantReadableHandle "hGetContents" h readAll
119 readAll hh@Handle__{..} = do
122 buf <- readIORef haCharBuffer
123 return $ if isEmptyBuffer buf
125 else T.singleton '\r'
126 | otherwise = throwIO (augmentIOError e "hGetContents" h)
128 buf <- readIORef haCharBuffer
129 t <- readChunk hh buf `catch` catchError
132 else (t:) `fmap` readChunks
134 (hh', _) <- hClose_help hh
135 return (hh'{haType=ClosedHandle}, T.concat ts)
137-- | Use a more efficient buffer size if we're reading in
138-- block-buffered mode with the default buffer size. When we can
139-- determine the size of the handle we're reading, set the buffer size
140-- to that, so that we can read the entire file in one chunk.
141-- Otherwise, use a buffer size of at least 16KB.
142chooseGoodBuffering :: Handle -> IO ()
143chooseGoodBuffering h = do
144 bufMode <- hGetBuffering h
146 BlockBuffering Nothing -> do
147 d <- catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->
148 if ioe_type e == InappropriateType
149 then return 16384 -- faster than the 2KB default
151 when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d
155-- | Read a single line from a handle.
156hGetLine :: Handle -> IO Text
157#if __GLASGOW_HASKELL__ <= 610
158hGetLine = fmap decodeUtf8 . B.hGetLine
160hGetLine = hGetLineWith T.concat
163-- | Write a string to a handle.
164hPutStr :: Handle -> Text -> IO ()
165#if __GLASGOW_HASKELL__ <= 610
166hPutStr h = B.hPutStr h . encodeUtf8
168-- This function is lifted almost verbatim from GHC.IO.Handle.Text.
171 wantWritableHandle "hPutStr" h $ \h_ -> do
172 bmode <- getSpareBuffer h_
173 return (bmode, haOutputNL h_)
176 (NoBuffering, _) -> hPutChars h str
177 (LineBuffering, buf) -> writeLines h nl buf str
178 (BlockBuffering _, buf)
179 | nl == CRLF -> writeBlocksCRLF h buf str
180 | otherwise -> writeBlocksRaw h buf str
182hPutChars :: Handle -> Stream Char -> IO ()
183hPutChars h (Stream next0 s0 _len) = loop s0
185 loop !s = case next0 s of
188 Yield x s' -> hPutChar h x >> loop s'
190-- The following functions are largely lifted from GHC.IO.Handle.Text,
191-- but adapted to a coinductive stream of data instead of an inductive
194-- We have several variations of more or less the same code for
195-- performance reasons. Splitting the original buffered write
196-- function into line- and block-oriented versions gave us a 2.1x
197-- performance improvement. Lifting out the raw/cooked newline
198-- handling gave a few more percent on top.
200writeLines :: Handle -> Newline -> Buffer CharBufElem -> Stream Char -> IO ()
201writeLines h nl buf0 (Stream next0 s0 _len) = outer s0 buf0
203 outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
207 Done -> commit n False{-no flush-} True{-release-} >> return ()
208 Skip s' -> inner s' n
210 | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
213 then do n1 <- writeCharBuf raw n '\r'
214 writeCharBuf raw n1 '\n'
215 else writeCharBuf raw n x
216 commit n' True{-needs flush-} False >>= outer s'
217 | otherwise -> writeCharBuf raw n x >>= inner s'
218 commit = commitBuffer h raw len
220writeBlocksCRLF :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()
221writeBlocksCRLF h buf0 (Stream next0 s0 _len) = outer s0 buf0
223 outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
227 Done -> commit n False{-no flush-} True{-release-} >> return ()
228 Skip s' -> inner s' n
230 | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
231 | x == '\n' -> do n1 <- writeCharBuf raw n '\r'
232 writeCharBuf raw n1 '\n' >>= inner s'
233 | otherwise -> writeCharBuf raw n x >>= inner s'
234 commit = commitBuffer h raw len
236writeBlocksRaw :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()
237writeBlocksRaw h buf0 (Stream next0 s0 _len) = outer s0 buf0
239 outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
243 Done -> commit n False{-no flush-} True{-release-} >> return ()
244 Skip s' -> inner s' n
246 | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
247 | otherwise -> writeCharBuf raw n x >>= inner s'
248 commit = commitBuffer h raw len
250-- This function is completely lifted from GHC.IO.Handle.Text.
251getSpareBuffer :: Handle__ -> IO (BufferMode, CharBuffer)
252getSpareBuffer Handle__{haCharBuffer=ref,
257 NoBuffering -> return (mode, error "no buffer!")
259 bufs <- readIORef spare_ref
262 BufferListCons b rest -> do
263 writeIORef spare_ref rest
264 return ( mode, emptyBuffer b (bufSize buf) WriteBuffer)
266 new_buf <- newCharBuffer (bufSize buf) WriteBuffer
267 return (mode, new_buf)
270-- This function is completely lifted from GHC.IO.Handle.Text.
271commitBuffer :: Handle -> RawCharBuffer -> Int -> Int -> Bool -> Bool
273commitBuffer hdl !raw !sz !count flush release =
274 wantWritableHandle "commitAndReleaseBuffer" hdl $
275 commitBuffer' raw sz count flush release
276{-# INLINE commitBuffer #-}
279-- | Write a string to a handle, followed by a newline.
280hPutStrLn :: Handle -> Text -> IO ()
281hPutStrLn h t = hPutStr h t >> hPutChar h '\n'
283-- | The 'interact' function takes a function of type @Text -> Text@
284-- as its argument. The entire input from the standard input device is
285-- passed to this function as its argument, and the resulting string
286-- is output on the standard output device.
287interact :: (Text -> Text) -> IO ()
288interact f = putStr . f =<< getContents
290-- | Read all user input on 'stdin' as a single string.
291getContents :: IO Text
292getContents = hGetContents stdin
294-- | Read a single line of user input from 'stdin'.
296getLine = hGetLine stdin
298-- | Write a string to 'stdout'.
299putStr :: Text -> IO ()
300putStr = hPutStr stdout
302-- | Write a string to 'stdout', followed by a newline.
303putStrLn :: Text -> IO ()
304putStrLn = hPutStrLn stdout
308-- /Note/: The behaviour of functions in this module depends on the
309-- version of GHC you are using.
311-- Beginning with GHC 6.12, text I\/O is performed using the system or
312-- handle's current locale and line ending conventions.
314-- Under GHC 6.10 and earlier, the system I\/O libraries do not
315-- support locale-sensitive I\/O or line ending conversion. On these
316-- versions of GHC, functions in this library all use UTF-8. What
317-- does this mean in practice?
319-- * All data that is read will be decoded as UTF-8.
321-- * Before data is written, it is first encoded as UTF-8.
323-- * On both reading and writing, the platform's native newline
324-- conversion is performed.
326-- If you must use a non-UTF-8 locale on an older version of GHC, you
327-- will have to perform the transcoding yourself, e.g. as follows:
329-- > import qualified Data.ByteString as B
330-- > import Data.Text (Text)
331-- > import Data.Text.Encoding (encodeUtf16)
333-- > putStr_Utf16LE :: Text -> IO ()
334-- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list