2011-01-30 10 views
6

में कई फ़ाइलों की सबसे छोटी फ़ाइलों को आसानी से कैसे पढ़ सकता हूं मेरे पास मेरे प्रोग्राम में "फ़ाइलें खोजें" फ़ंक्शन है जो मेरे प्रोग्राम को पढ़े गए .ged प्रत्यय वाले टेक्स्ट फ़ाइलों को मिलेगा। मैं एक अन्वेषक की तरह खिड़की है कि इस तरह दिखता है में पाया परिणाम प्रदर्शित:मैं डेल्फी

enter image description here

मैं मानक FindFirst/FindNext तरीकों का उपयोग, और यह बहुत जल्दी काम करता है। ऊपर दिखाए गए 584 फाइलें कुछ सेकंड के भीतर पाई जाती हैं और प्रदर्शित होती हैं।

जो मैं अब करना चाहता हूं वह प्रदर्शन में दो कॉलम जोड़ता है जो "स्रोत" और "संस्करण" दिखाता है जो इन फ़ाइलों में से प्रत्येक में निहित है। यह जानकारी प्रत्येक फ़ाइल के पहले 10 लाइनों के भीतर आम तौर पर पाया जाता है, लाइनों है कि तरह लग रहे पर:

1 SOUR FTM 
2 VERS Family Tree Maker (20.0.0.368) 

अब मैं इस बहुत जल्दी अपने आप को पार्स कोई समस्या नहीं है, और कहा कि मैं क्या पूछ रहा हूँ नहीं है।

मुझे सहायता की आवश्यकता है कि इन फ़ाइलों से पहली 10 या तो लाइनों को सबसे तेज़ी से कैसे लोड किया जाए ताकि मैं उन्हें पार्स कर सकूं।

मैंने स्ट्रिंगलिस्ट को लोड करने का प्रयास किया है। लोडफ्रॉमफ़ाइल, लेकिन 1 एमबी से ऊपर की बड़ी फ़ाइलों को लोड करने में बहुत अधिक समय लगता है।

चूंकि मुझे केवल पहली 10 लाइनों की आवश्यकता है या तो, मैं उन्हें सर्वश्रेष्ठ कैसे प्राप्त करूं?

मैं डेल्फी 200 का उपयोग कर रहा हूं, और मेरी इनपुट फाइल यूनिकोड हो सकती है या नहीं, इसलिए इसे किसी भी एन्कोडिंग के लिए काम करने की आवश्यकता है।


फॉलोअप: धन्यवाद एंटोनियो,

मैं यह कर समाप्त हो गया जो ठीक काम करता है:

var 
    CurFileStream: TStream; 
    Buffer: TBytes; 
    Value: string; 
    Encoding: TEncoding; 

try 
    CurFileStream := TFileStream.Create(folder + FileName, fmOpenRead); 
    SetLength(Buffer, 256); 
    CurFileStream.Read(Buffer[0], 256); 
    TEncoding.GetBufferEncoding(Buffer, Encoding); 
    Value := Encoding.GetString(Buffer); 
    ... 
    (parse through Value to get what I want) 
    ... 
finally 
    CurFileStream.Free; 
end; 
+0

TStrings.LoadFromFile बहुत अक्षम है, इसके बारे में भूल जाओ। बॉक्स से बाहर सोचें और बाइट्स की संख्या (उदा।: न्यूमलाइन * एवीलाइनलाइनेंथ) पढ़ें, लाइनस्टार्ट के साथ छिड़काव करें और फिर टीएसट्रिंग्स –

+0

में विभाजित करें, वास्तव में, वर्म, यह उतना बुरा नहीं है जितना आप सोचेंगे। यह लगभग 10 एमबी एक सेकेंड पढ़ और लोड कर सकता है। जब भी मुझे उन फ़ाइलों में ग्रंथों की खोज करनी पड़ती है तब भी मैं इसका सफलतापूर्वक उपयोग करता हूं। लेकिन पूरी फाइलों को लोड करने के लिए इसका उपयोग क्यों करें और उपयोगकर्ता को केवल 40 सेकंड प्रतीक्षा करें जब केवल पहले कुछ लाइनों की आवश्यकता हो। – lkessler

उत्तर

14

उपयोग TFileStream और जरूरत बाइट्स की पढ़ें विधि पढ़ संख्या के साथ। यहां बिटमैप जानकारी पढ़ने का उदाहरण दिया गया है जो फ़ाइल की शुरुआत पर भी संग्रहीत है।

http://www.delphidabbler.com/tips/19

+4

+1 मैं इसके लिए एक TFileStream का उपयोग करूंगा क्योंकि यह देशी ओएस फ़ाइल एपीआई को बहुत अच्छी तरह से लपेटता है। –

+5

+1। बस डेटा के पहले 4 किलोबाइट्स को पढ़ें: संभवतः पहले कुछ पंक्तियों को पूरी तरह से शामिल करने के लिए पर्याप्त है, और यह डिस्क से किसी भी तरह से पढ़ने वाले डेटा की न्यूनतम मात्रा है। यदि आप कई फाइलों से पढ़ रहे हैं (और 584 फाइलें बिल्कुल "बहुत" नहीं हैं), और आप फैंसी प्राप्त करना चाहते हैं, तो आप CreateFile का उपयोग करके, कैंडिंग के बिना फ़ाइलों को खोलना और हैंडल को थंडलस्ट्रीम में पास करना चाहते हैं: यह प्रदान कर सकता है सुधार की एक छोटी सी छोटी मात्रा क्योंकि ओएस जानता है कि वह डेटा कैश न करें जो कि फिर से अनुरोध नहीं किया जा रहा है। –

+2

TFileStream में एक readLn क्षमता की कमी है। क्या होगा यदि शायद पर्याप्त नहीं है? –

4

बस ब्लॉक को पढ़ना (TStringList अंतर्निहित कार्यक्षमता का उपयोग नहीं) के लिए फ़ाइल अपने आप को खोलने के लिए, और फ़ाइल के पहले खंड को पढ़ने, और फिर आप उदाहरण के लिए strings.SetText के साथ एक stringlist है कि ब्लॉक लोड कर सकते हैं() (यदि आप ब्लॉक फ़ंक्शंस का उपयोग कर रहे हैं) या बस स्ट्रिंग्स। लोडफ्रेमस्ट्रीम() यदि आप स्ट्रीम का उपयोग करके अपने ब्लॉक लोड कर रहे हैं।

मैं व्यक्तिगत रूप से केवल FileRead/FileWrite ब्लॉक फ़ंक्शंस के साथ जाऊंगा, और ब्लॉक को बफर में लोड कर दूंगा। आप similair winapi फ़ंक्शंस का भी उपयोग कर सकते हैं, लेकिन किसी भी कारण से यह और अधिक कोड है।

ओएस ब्लॉक में फ़ाइलों को पढ़ता है, जो कम से कम 512 बाइट्स लगभग किसी भी मंच/फाइल सिस्टम पर बड़े होते हैं, इसलिए आप पहले 512 बाइट पढ़ सकते हैं (और उम्मीद है कि आपको सभी 10 लाइनें मिलेंगी, जो आपकी लाइनें आम तौर पर कम होंगी पर्याप्त)। यह (व्यावहारिक रूप से) 100 या 200 बाइट पढ़ने के रूप में तेज़ होगा।

फिर यदि आप देखते हैं कि आपके तारों की वस्तुओं में केवल 10 लाइनें हैं, तो बस अगले 512 बाइट ब्लॉक पढ़ें और फिर से पार्स करने का प्रयास करें। (या बस 1024, 2048 और ब्लॉक पर जाएं, कई प्रणालियों पर यह संभवतः 512 ब्लॉक जितना तेज होगा, क्योंकि फाइल सिस्टम क्लस्टर आकार आम तौर पर 512 बाइट से बड़े होते हैं)।

पीएस।इसके अलावा, Winapi फ़ाइल फ़ंक्शंस (CreateFile और ऐसे) में थ्रेड या एसिंक्रोनस कार्यक्षमता का उपयोग करके, आप उस डेटा को असीमित रूप से फ़ाइलों से लोड कर सकते हैं, जबकि आपका शेष एप्लिकेशन काम करता है। विशेष रूप से, इंटरफ़ेस बड़ी निर्देशिकाओं के पढ़ने के दौरान जमा नहीं होगा।

यह आपकी जानकारी को लोड करने में तेजी से दिखाई देगा, (क्योंकि फाइल सूची सीधे लोड हो जाएगी, और फिर कुछ मिलीसेकंड बाद में बाकी जानकारी आ जाएगी), जबकि वास्तव में वास्तविक पढ़ने की गति में वृद्धि नहीं होती है।

यह केवल तभी करें जब आपने अन्य तरीकों का प्रयास किया हो और आपको लगता है कि आपको अतिरिक्त बढ़ावा की आवश्यकता है।

+0

फ़ाइल रीड/फ़ाइलवाइट एपीआई फ़ंक्शंस –

+0

'रीडफाइल()' और 'लिखेंफाइल() 'Win32 API फ़ंक्शन हैं। 'FileRead() 'और' FileWrite()' उनके चारों ओर SysUtils wrappers हैं। –

0

कभी-कभी पुरानीस्कूल पास्कल शैली खराब नहीं होती है। भले ही गैर-ओओ फ़ाइल का उपयोग अब बहुत लोकप्रिय प्रतीत नहीं होता है, ReadLn(F,xxx) अभी भी आपकी तरह की स्थितियों में बहुत ठीक काम करता है।

नीचे दिया गया कोड TDictionary में जानकारी (फ़ाइल नाम, स्रोत और संस्करण) लोड करता है ताकि आप इसे आसानी से देख सकें, या आप आभासी मोड में एक सूचीदृश्य का उपयोग कर सकते हैं, और ondata यहां तक ​​कि आग लगने पर इस सूची में सामान देख सकते हैं ।

चेतावनी: नीचे कोड यूनिकोड के साथ काम नहीं करता है।

program Project101; 
{$APPTYPE CONSOLE} 

uses 
    IoUtils, Generics.Collections, SysUtils; 

type 
    TFileInfo=record 
    FileName, 
    Source, 
    Version:String; 
    end; 

function LoadFileInfo(var aFileInfo:TFileInfo):Boolean; 
var 
    F:TextFile; 
begin 
    Result := False; 
    AssignFile(F,aFileInfo.FileName); 
    {$I-} 
    Reset(F); 
    {$I+} 
    if IOResult = 0 then 
    begin 
    ReadLn(F,aFileInfo.Source); 
    ReadLn(F,aFileInfo.Version); 
    CloseFile(F); 
    Exit(True) 
    end 
    else 
    WriteLn('Could not open ', aFileInfo.FileName); 
end; 

var 
    FileInfo:TFileInfo; 
    Files:TDictionary<string,TFileInfo>; 
    S:String; 
begin 
    Files := TDictionary<string,TFileInfo>.Create; 
    try 
    for S in TDirectory.GetFiles('h:\WINDOWS\system32','*.xml') do 
    begin 
     WriteLn(S); 
     FileInfo.FileName := S; 
     if LoadFileInfo(FileInfo) then 
     Files.Add(S,FileInfo); 
    end; 

    // showing file information... 
    for FileInfo in Files.Values do 
     WriteLn(FileInfo.Source, ' ',FileInfo.Version); 
    finally 
    Files.Free 
    end; 
    WriteLn; 
    WriteLn('Done. Press any key to quit . . .'); 
    ReadLn; 
end. 
+3

बस ध्यान रखें कि D2009 + में पढ़ें/लिखें (एलएन) विधियां * नहीं * समर्थन यूनिकोड। –

+1

-1 सवाल यह बताता है कि फ़ाइलें यूनिकोड एन्कोडिंग –

+0

-1 का उपयोग उसी कारण से @ डेविड के रूप में कर सकती हैं। यूनिकोड समर्थन की कमी इस जवाब को व्यवहार्य नहीं बनाती है। –

3

आप एक TStreamReader का उपयोग इस तरह के एक TFileStream रूप में किसी भी TStream वस्तु से अलग-अलग लाइनों, पढ़ने के लिए कर सकते हैं। यहां तक ​​कि तेज फ़ाइल I/O के लिए, आप TCustomMemoryStream के साथ मेमोरी-मैप किए गए दृश्यों का उपयोग कर सकते हैं।

+0

TStreamReader एक रीडलाइन समकक्ष कर सकता है? –

+0

मैंने रेमी के सुझाव के आधार पर एक उदाहरण लिखा, जैसा कि मेरा जवाब है। –

+0

@ वॉरेन: हां। TStreamReader में सार्वजनिक रीडलाइन() विधि उपलब्ध है। –

2

ठीक है, मैंने अपना पहला जवाब हटा दिया। ऊपर रेमी के पहले सुझाव का उपयोग करके, मैंने अंतर्निहित सामग्री के साथ फिर कोशिश की। मुझे यहां क्या पसंद नहीं है यह है कि आपको दो वस्तुओं को बनाना और मुक्त करना है। मैं मैं अपने ही वर्ग बनाना होगा इस लपेट के लिए लगता है:

var 
    fs:TFileStream; 
    tr:TTextReader; 
    filename:String; 
begin 
    filename := 'c:\temp\textFileUtf8.txt'; 
    fs := TFileStream.Create(filename, fmOpenRead); 
    tr := TStreamReader.Create(fs); 
    try 
     Memo1.Lines.Add(tr.ReadLine); 

    finally 
    tr.Free; 
    fs.Free; 
    end; 
end; 

तो किसी को क्या मैं यहाँ पहले था में रुचि है, यह यूनिकोड फाइलों के साथ काम नहीं की समस्या थी।

+0

वैकल्पिक, वॉरेन के लिए धन्यवाद। मैं पहले से ही एंटोनियो के सुझाव के रूप में TFileStream को लागू करने में कामयाब रहा था, और यह काफी अच्छा काम कर रहा है कि मुझे कुछ और करने की कोशिश नहीं है। हालांकि, मैं इसे एक विकल्प के रूप में याद रखूंगा। – lkessler

+0

रीडलाइन के कारण बेहतर समाधान के लिए +1, लेकिन मुझे यकीन नहीं है कि यह * तेज * –

+0

है TStreamReader में कई रचनाकार हैं जो आपको एक अलग TStream ऑब्जेक्ट पॉइंटर के बजाय फ़ाइल नाम निर्दिष्ट करने देते हैं। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^