2012-04-04 27 views
7

मैं एक फ़ाइल को पार्स करने के लिए है, और वास्तव में एक यह पहली बार पढ़ने के लिए, यहाँ मेरा कार्यक्रम है:Data.ByteString के साथ 7 जीबी फ़ाइल का विश्लेषण कैसे करें?

import qualified Data.ByteString.Char8 as B 
import System.Environment  

main = do 
args  <- getArgs 
let path = args !! 0 
content <- B.readFile path 
let lines = B.lines content 
foobar lines 

foobar :: [B.ByteString] -> IO() 
foobar _ = return() 

लेकिन संकलन के बाद,

> ghc --make -O2 tmp.hs 

निष्पादन निम्न त्रुटि जब माध्यम से चला जाता एक 7 गीगाबाइट फ़ाइल के साथ बुलाया।

> ./tmp big_big_file.dat 
> tmp: {handle: big_big_file.dat}: hGet: illegal ByteString size (-1501792951): illegal operation 

किसी भी उत्तर के लिए धन्यवाद!

+0

क्या मंच आप पर कर रहे हैं? –

+0

@DanielFischer आप 'प्लेटफॉर्म' क्या कहते हैं? अगर यह ऑपरेटिंग सिस्टम है, तो मैं लिनक्स उबंटू 10.4 का उपयोग कर रहा हूं। धन्यवाद –

+0

32 बिट या 64? आम तौर पर एक 32 बिट ओएस को बड़ी फ़ाइलों के साथ समस्याएं होने वाली हैं। –

उत्तर

5

सख्त ByteString ही स्मृति के लिए 2 GiB समर्थन करते हैं। इसे काम करने के लिए आपको lazy ByteStrings का उपयोग करने की आवश्यकता है।

+0

व्हाउउ! धन्यवाद @dflemstr यह आपके द्वारा बताए गए 'Data.Byteestring.Char8' को' Data.Bytestring.Lazy.Char8' 'में बदलकर काम करता है। –

9

ByteString रों की लंबाई Int हैं। यदि Int 32 बिट, एक 7GB फ़ाइल Int की सीमा पार हो जाएगी और बफर अनुरोध एक गलत आकार के लिए किया जाएगा और आसानी से एक नकारात्मक आकार का अनुरोध कर सकते हैं।

readFile के लिए कोड बफर अनुरोध

readFile :: FilePath -> IO ByteString 
readFile f = bracket (openBinaryFile f ReadMode) hClose 
    (\h -> hFileSize h >>= hGet h . fromIntegral) 

के लिए और अगर है कि अतिप्रवाह, एक "अवैध ByteString आकार" त्रुटि या एक विभाजन गलती सबसे अधिक संभावना परिणाम हैं Int फ़ाइल आकार बदल देता है।

बिल्कुल संभव हो तो, कि बड़ी फ़ाइलों को संभालने के लिए उपयोग करते हैं आलसी ByteString रों। आपके मामले में, आप काफी यह संभव बनाने के लिए, के बाद से साथ 32 बिट Int रों, एक 7GB ByteString बनाने के लिए असंभव है।

आप की जरूरत लाइनों प्रसंस्करण के लिए सख्त ByteString रों होने के लिए, और कोई लाइन बेहद लंबा है, तो आप उस

import qualified Data.ByteString.Lazy.Char8 as LC 
import qualified Data.ByteString.Char8 as C 

main = do 
    ... 
    content <- LC.readFile path 
    let llns = LC.lines content 
     slns = map (C.concat . LC.toChunks) llns 
    foobar slns 

प्राप्त करने के लिए आलसी ByteString रों के माध्यम से जा सकते हैं, लेकिन आप करने के लिए अपने संसाधन संशोधित कर सकते हैं, तो आलसी ByteString एस के साथ सौदा करें, जो शायद समग्र रूप से बेहतर होगा।

+0

धन्यवाद @ डैनियल फिशर! यह अब मुझे स्पष्ट है, लेकिन मैं अपनी फाइल को पार्स करने के लिए क्या कर सकता हूं? –

+0

चूंकि आप इसे लाइनों में विभाजित करते हैं, यदि आप सुनिश्चित हैं कि कोई लाइन 2 जीबी से अधिक नहीं है, तो आप फ़ाइल को आलसी 'बाइटस्ट्रिंग' के रूप में पढ़ सकते हैं, इसे लाइनों में विभाजित कर सकते हैं और यदि आवश्यक हो, तो प्रत्येक पंक्ति से सख्त 'बाइटस्ट्रिंग' बनाएं। या आप फ़ाइल लाइन-दर-रेखा पढ़ सकते हैं। सर्वोत्तम दृष्टिकोण निर्धारित करने के लिए अधिक जानकारी की आवश्यकता है (लेकिन शायद यह आलसी के माध्यम से जा रहा है)। –