Wie kann ich mehrere Dateien als einzelnen ByteString träge mit konstantem Speicher lesen?
Wenn Sie eine konstante Speichernutzung wünschen, benötigen Sie Data.ByteString.Lazy
. Ein strenger ByteString
kann nicht träge gelesen werden und würde O(sum of filesizes)
Speicher benötigen.
Für eine nicht zu große Anzahl von Dateien, einfach zu lesen, sie alle (D.B.L.readFile
liest träge) und die Ergebnisse verketten ist gut,
import qualified Data.ByteString.Lazy as L
readFiles :: [FilePath] -> IO L.ByteString
readFiles = fmap L.concat . mapM L.readFile
Die mapM L.readFile
die Dateien öffnen, aber nur den Inhalt von jedem gelesen Datei, wenn es angefordert wird.
Wenn die Anzahl der Dateien groß ist, so dass die Grenze der offenen Dateizugriffsnummern, die vom Betriebssystem für einen einzelnen Prozess zulässig sind, erschöpft sein kann, benötigen Sie etwas komplizierteres. Sie können Ihre eigene faul Version von mapM
,
import System.IO.Unsafe (unsafeInterleaveIO)
mapM_lazy :: [IO a] -> IO [a]
mapM_lazy [] = return []
mapM_lazy (x:xs) = do
r <- x
rs <- unsafeInterleaveIO (mapM_lazy xs)
return (r:rs)
so dass jede Datei nur dann geöffnet werden, wenn sein Inhalt benötigt werden, wenn zuvor Dateien lesen kann bereits geschlossen kochen. Es gibt eine geringe Möglichkeit, dass das immer noch in Ressourcengrenzen läuft, da die Zeit des Schließens der Handles nicht garantiert ist.
Oder Sie können Ihre bevorzugten iteratee
, enumerator
, conduit
oder was auch immer Paket, das das Problem auf systematische Weise löst. Jeder von ihnen hat seine eigenen Vor- und Nachteile in Bezug auf die anderen und eliminiert bei korrekter Codierung die Möglichkeit, dass er versehentlich das Ressourcenlimit erreicht.
Danke, ich hätte erwähnen sollen, dass ich Data.ByteString.Lazy bereits verwendet habe. Dies funktionierte gut mit der Speichernutzung, die mit jedem offenen Griff etwas anstieg. Auch danke, dass ich auf die zusätzlichen Pakete hingewiesen habe. Ich habe gerade begonnen, Haskell zu lernen und bin noch nicht auf sie gestoßen. –