on master help sign in
Expose filesystem file module (#2162)
commitdae14c54195039be97c85b908642b93bd75e816b authorRanjeet Ranjan <ranjeetr@composewell.com> dateTue 13 Dec 2022, 02:32 (4 years ago) parentd7ab86a
3 files changed+93−27
core/src/Streamly/FileSystem/File.hs+56 core/src/Streamly/Internal/FileSystem/File.hs+36−27 core/streamly-core.cabal+1
core/src/Streamly/FileSystem/File.hsnew file+56
@@ -0,0 +1,56 @@
1+-- |
2+-- Module : Streamly.FileSystem.File
3+-- Copyright : (c) 2019 Composewell Technologies
4+--
5+-- License : BSD3
6+-- Maintainer : streamly@composewell.com
7+-- Stability : pre-release
8+-- Portability : GHC
9+--
10+-- Read and write streams and arrays to and from files specified by their paths
11+-- in the file system. Unlike the handle based APIs which can have a read/write
12+-- session consisting of multiple reads and writes to the handle, these APIs
13+-- are one shot read or write APIs. These APIs open the file handle, perform
14+-- the requested operation and close the handle. Thease are safer compared to
15+-- the handle based APIs as there is no possibility of a file descriptor
16+-- leakage.
17+--
18+-- > import qualified Streamly.FileSystem.File as File
19+--
20+module Streamly.FileSystem.File
21+ (
22+ -- * Streaming IO
23+ -- | Stream data to or from a file or device sequentially. When reading,
24+ -- the stream is lazy and generated on-demand as the consumer consumes it.
25+ -- Read IO requests to the IO device are performed in chunks limited to a
26+ -- maximum size of 32KiB, this is referred to as @defaultChunkSize@ in the
27+ -- documentation. One IO request may or may not read the full
28+ -- chunk. If the whole stream is not consumed, it is possible that we may
29+ -- read slightly more from the IO device than what the consumer needed.
30+ -- Unless specified otherwise in the API, writes are collected into chunks
31+ -- of @defaultChunkSize@ before they are written to the IO device.
32+
33+ -- Streaming APIs work for all kind of devices, seekable or non-seekable;
34+ -- including disks, files, memory devices, terminals, pipes, sockets and
35+ -- fifos. While random access APIs work only for files or devices that have
36+ -- random access or seek capability for example disks, memory devices.
37+ -- Devices like terminals, pipes, sockets and fifos do not have random
38+ -- access capability.
39+
40+ -- ** File IO Using Handle
41+ withFile
42+
43+ -- ** Streams
44+ , read
45+ , readChunksWith
46+ , readChunks
47+
48+ -- ** Folds
49+ , write
50+ , writeWith
51+ , writeChunks
52+ )
53+where
54+
55+import Streamly.Internal.FileSystem.File
56+import Prelude hiding (read)
core/src/Streamly/Internal/FileSystem/File.hs+36−27
@@ -147,7 +147,7 @@ import qualified Streamly.Data.Stream as S (fold, bracketIO, mapM)
147147-- /Pre-release/
148148--
149149{-# INLINE withFile #-}
150−withFile :: (MonadCatch m, MonadIO m)
150+withFile :: (MonadIO m, MonadCatch m)
151151 => FilePath -> IOMode -> (Handle -> Stream m a) -> Stream m a
152152withFile file mode = S.bracketIO (openFile file mode) hClose
153153
@@ -160,12 +160,12 @@ withFile file mode = S.bracketIO (openFile file mode) hClose
160160-- /Pre-release/
161161--
162162{-# INLINE usingFile #-}
163−usingFile :: (MonadCatch m, MonadIO m)
163+usingFile :: (MonadIO m, MonadCatch m)
164164 => Unfold m Handle a -> Unfold m FilePath a
165165usingFile = UF.bracketIO (`openFile` ReadMode) hClose
166166
167167{-# INLINE usingFile2 #-}
168−usingFile2 :: (MonadCatch m, MonadIO m)
168+usingFile2 :: (MonadIO m, MonadCatch m)
169169 => Unfold m (x, Handle) a -> Unfold m (x, FilePath) a
170170usingFile2 = UF.bracketIO before after
171171
@@ -178,7 +178,7 @@ usingFile2 = UF.bracketIO before after
178178 after (_, h) = hClose h
179179
180180{-# INLINE usingFile3 #-}
181−usingFile3 :: (MonadCatch m, MonadIO m)
181+usingFile3 :: (MonadIO m, MonadCatch m)
182182 => Unfold m (x, y, z, Handle) a -> Unfold m (x, y, z, FilePath) a
183183usingFile3 = UF.bracketIO before after
184184
@@ -202,14 +202,16 @@ usingFile3 = UF.bracketIO before after
202202
203203-- | Write an array to a file. Overwrites the file if it exists.
204204--
205−-- @since 0.7.0
205+-- /Pre-release/
206+--
206207{-# INLINABLE putChunk #-}
207208putChunk :: FilePath -> Array a -> IO ()
208209putChunk file arr = SIO.withFile file WriteMode (`FH.putChunk` arr)
209210
210211-- | append an array to a file.
211212--
212−-- @since 0.7.0
213+-- /Pre-release/
214+--
213215{-# INLINABLE appendArray #-}
214216appendArray :: FilePath -> Array a -> IO ()
215217appendArray file arr = SIO.withFile file AppendMode (`FH.putChunk` arr)
@@ -222,16 +224,17 @@ appendArray file arr = SIO.withFile file AppendMode (`FH.putChunk` arr)
222224-- The maximum size of a single array is specified by @size@. The actual size
223225-- read may be less than or equal to @size@.
224226--
225−-- @since 0.9.0
227+-- /Pre-release/
228+--
226229{-# INLINE readChunksWith #-}
227−readChunksWith :: (MonadCatch m, MonadIO m)
230+readChunksWith :: (MonadIO m, MonadCatch m)
228231 => Int -> FilePath -> Stream m (Array Word8)
229232readChunksWith size file =
230233 withFile file ReadMode (FH.readChunksWith size)
231234
232235{-# DEPRECATED toChunksWithBufferOf "Please use 'readChunksWith' instead" #-}
233236{-# INLINE toChunksWithBufferOf #-}
234−toChunksWithBufferOf :: (MonadCatch m, MonadIO m)
237+toChunksWithBufferOf :: (MonadIO m, MonadCatch m)
235238 => Int -> FilePath -> Stream m (Array Word8)
236239toChunksWithBufferOf = readChunksWith
237240
@@ -243,15 +246,16 @@ toChunksWithBufferOf = readChunksWith
243246--
244247-- > readChunks = readChunksWith defaultChunkSize
245248--
246−-- @since 0.7.0
249+-- /Pre-release/
250+--
247251{-# INLINE readChunks #-}
248−readChunks :: (MonadCatch m, MonadIO m)
252+readChunks :: (MonadIO m, MonadCatch m)
249253 => FilePath -> Stream m (Array Word8)
250254readChunks = readChunksWith defaultChunkSize
251255
252256{-# DEPRECATED toChunks "Please use 'readChunks' instead" #-}
253257{-# INLINE toChunks #-}
254−toChunks :: (MonadCatch m, MonadIO m) => FilePath -> Stream m (Array Word8)
258+toChunks :: (MonadIO m, MonadCatch m) => FilePath -> Stream m (Array Word8)
255259toChunks = readChunks
256260
257261-------------------------------------------------------------------------------
@@ -270,14 +274,14 @@ toChunks = readChunks
270274-- /Pre-release/
271275--
272276{-# INLINE chunkReaderWith #-}
273−chunkReaderWith :: (MonadCatch m, MonadIO m)
277+chunkReaderWith :: (MonadIO m, MonadCatch m)
274278 => Unfold m (Int, FilePath) (Array Word8)
275279chunkReaderWith = usingFile2 FH.chunkReaderWith
276280
277281{-# DEPRECATED readChunksWithBufferOf
278282 "Please use 'chunkReaderWith' instead" #-}
279283{-# INLINE readChunksWithBufferOf #-}
280−readChunksWithBufferOf :: (MonadCatch m, MonadIO m)
284+readChunksWithBufferOf :: (MonadIO m, MonadCatch m)
281285 => Unfold m (Int, FilePath) (Array Word8)
282286readChunksWithBufferOf = chunkReaderWith
283287
@@ -290,14 +294,14 @@ readChunksWithBufferOf = chunkReaderWith
290294--
291295-- /Pre-release/
292296{-# INLINE chunkReaderFromToWith #-}
293−chunkReaderFromToWith :: (MonadCatch m, MonadIO m) =>
297+chunkReaderFromToWith :: (MonadIO m, MonadCatch m) =>
294298 Unfold m (Int, Int, Int, FilePath) (Array Word8)
295299chunkReaderFromToWith = usingFile3 FH.chunkReaderFromToWith
296300
297301{-# DEPRECATED readChunksFromToWith
298302 "Please use 'chunkReaderFromToWith' instead" #-}
299303{-# INLINE readChunksFromToWith #-}
300−readChunksFromToWith :: (MonadCatch m, MonadIO m) =>
304+readChunksFromToWith :: (MonadIO m, MonadCatch m) =>
301305 Unfold m (Int, Int, Int, FilePath) (Array Word8)
302306readChunksFromToWith = chunkReaderFromToWith
303307
@@ -309,7 +313,7 @@ readChunksFromToWith = chunkReaderFromToWith
309313--
310314-- /Pre-release/
311315{-# INLINE chunkReader #-}
312−chunkReader :: (MonadCatch m, MonadIO m) => Unfold m FilePath (Array Word8)
316+chunkReader :: (MonadIO m, MonadCatch m) => Unfold m FilePath (Array Word8)
313317chunkReader = usingFile FH.chunkReader
314318
315319-- | Unfolds the tuple @(bufsize, filepath)@ into a byte stream, read requests
@@ -317,12 +321,12 @@ chunkReader = usingFile FH.chunkReader
317321--
318322-- /Pre-release/
319323{-# INLINE readerWith #-}
320−readerWith :: (MonadCatch m, MonadIO m) => Unfold m (Int, FilePath) Word8
324+readerWith :: (MonadIO m, MonadCatch m) => Unfold m (Int, FilePath) Word8
321325readerWith = usingFile2 FH.readerWith
322326
323327{-# DEPRECATED readWithBufferOf "Please use 'readerWith' instead" #-}
324328{-# INLINE readWithBufferOf #-}
325−readWithBufferOf :: (MonadCatch m, MonadIO m) =>
329+readWithBufferOf :: (MonadIO m, MonadCatch m) =>
326330 Unfold m (Int, FilePath) Word8
327331readWithBufferOf = readerWith
328332
@@ -332,7 +336,7 @@ readWithBufferOf = readerWith
332336--
333337-- /Pre-release/
334338{-# INLINE reader #-}
335−reader :: (MonadCatch m, MonadIO m) => Unfold m FilePath Word8
339+reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
336340reader = UF.many A.reader (usingFile FH.chunkReader)
337341
338342-- | Generate a stream of bytes from a file specified by path. The stream ends
@@ -342,12 +346,12 @@ reader = UF.many A.reader (usingFile FH.chunkReader)
342346-- /Pre-release/
343347--
344348{-# INLINE read #-}
345−read :: (MonadCatch m, MonadIO m) => FilePath -> Stream m Word8
349+read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
346350read file = AS.concat $ withFile file ReadMode FH.readChunks
347351
348352{-# DEPRECATED toBytes "Please use 'read' instead" #-}
349353{-# INLINE toBytes #-}
350−toBytes :: (MonadCatch m, MonadIO m) => FilePath -> Stream m Word8
354+toBytes :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
351355toBytes = read
352356
353357{-
@@ -373,7 +377,8 @@ fromChunksMode mode file xs = S.fold drain $
373377
374378-- | Write a stream of arrays to a file. Overwrites the file if it exists.
375379--
376−-- @since 0.7.0
380+-- /Pre-release/
381+--
377382{-# INLINE fromChunks #-}
378383fromChunks :: (MonadIO m, MonadCatch m)
379384 => FilePath -> Stream m (Array a) -> m ()
@@ -391,7 +396,8 @@ fromChunks = fromChunksMode WriteMode
391396-- be written to the IO device as soon as we collect the specified number of
392397-- input elements.
393398--
394−-- @since 0.9.0
399+-- /Pre-release/
400+--
395401{-# INLINE fromBytesWith #-}
396402fromBytesWith :: (MonadIO m, MonadCatch m)
397403 => Int -> FilePath -> Stream m Word8 -> m ()
@@ -476,7 +482,8 @@ write = writeWith defaultChunkSize
476482
477483-- | Append a stream of arrays to a file.
478484--
479−-- @since 0.7.0
485+-- /Pre-release/
486+--
480487{-# INLINE appendChunks #-}
481488appendChunks :: (MonadIO m, MonadCatch m)
482489 => FilePath -> Stream m (Array a) -> m ()
@@ -486,7 +493,8 @@ appendChunks = fromChunksMode AppendMode
486493-- be written to the IO device as soon as we collect the specified number of
487494-- input elements.
488495--
489−-- @since 0.9.0
496+-- /Pre-release/
497+--
490498{-# INLINE appendWith #-}
491499appendWith :: (MonadIO m, MonadCatch m)
492500 => Int -> FilePath -> Stream m Word8 -> m ()
@@ -497,7 +505,8 @@ appendWith n file xs = appendChunks file $ AS.arraysOf n xs
497505-- is appended to the file. If the file does not exist it is created. File is
498506-- locked using single writer locking mode.
499507--
500−-- @since 0.7.0
508+-- /Pre-release/
509+--
501510{-# INLINE append #-}
502511append :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8 -> m ()
503512append = appendWith defaultChunkSize
core/streamly-core.cabal+1
@@ -390,6 +390,7 @@ library
390390 , Streamly.Data.Stream
391391 , Streamly.Data.Unfold
392392 , Streamly.FileSystem.Dir
393+ , Streamly.FileSystem.File
393394 , Streamly.FileSystem.Handle
394395 , Streamly.Unicode.Parser
395396 , Streamly.Unicode.Stream