想讀取大型TXT檔案 |
答題得分者是:jow
|
rockhaword
一般會員 發表:3 回覆:5 積分:1 註冊:2011-05-30 發送簡訊給我 |
我想設計一個程式可以讀取大型文字檔.txt(檔案大小1.3G)
檔案總共有90多萬筆資料 一行一筆 每一筆的長度不一 不知道有沒有方法可以抓取想要的第 i 行的資料就好 目前測試了StringList的方法 但是因為檔案過大 會發生Out of memory [code delphi] if (OpenDialog1->Execute()){ TStringList *SLTmp = new TStringList(); SLTmp->LoadFromFile(OpenDialog1->FileName); for (int i=0; i < SLTmp->Count ; i ) { Memo1->Lines->Add(SLTmp->Strings[i]); }//end of while ( i < SLTmp->Count) delete SLTmp; } [/code] 不一定要一次讀完整個檔案 請問有沒有方法可以只抓取想要的第 i 行的資料就好 編輯記錄
rockhaword 重新編輯於 2011-06-23 01:18:03, 註解 無‧
rockhaword 重新編輯於 2011-06-23 01:19:32, 註解 無‧ rockhaword 重新編輯於 2011-06-23 01:20:05, 註解 無‧ |
mephise
高階會員 發表:4 回覆:149 積分:205 註冊:2004-02-09 發送簡訊給我 |
文字檔就是必須循序讀取, 如果可以直接跳到第N行的話, 那資料庫也沒啥用了
檔案太大可以試試看這個方式: [code delphi] var f: TextFile str: String; begin AssignFile(f, 'C:\data.txt'); Reset(f); while not Eof(f) do begin Readln(f, str); // 把資料一次一行讀到 str, 然後再判斷 str 是不是你要的資料 end; end; [/code]
------
Mephise Chen 前興德工程師 |
ANDY8C
資深會員 發表:114 回覆:582 積分:299 註冊:2006-10-29 發送簡訊給我 |
|
rockhaword
一般會員 發表:3 回覆:5 積分:1 註冊:2011-05-30 發送簡訊給我 |
感謝回覆
用的大大的方法試過了 讀取小型檔案OK沒問題 但是讀取1.3G的大檔案就完全沒反應 還是感謝大大的回覆 ===================引 用 mephise 文 章=================== 文字檔就是必須循序讀取, 如果可以直接跳到第N行的話, 那資料庫也沒啥用了 檔案太大可以試試看這個方式: [code delphi] var f: TextFile str: String; begin AssignFile(f, 'C:\data.txt'); Reset(f); while not Eof(f) do begin Readln(f, str); // 把資料一次一行讀到 str, 然後再判斷 str 是不是你要的資料 end; end; [/code] |
mephise
高階會員 發表:4 回覆:149 積分:205 註冊:2004-02-09 發送簡訊給我 |
沒反應不代表失敗喔, 可能只是系統I/O一直在忙碌而以
Windows 系統有個通病, 當它正在忙綠時, 你如果點一下視窗, 它就會顯示 "這個程式已經沒有回應 bala bala ........." 你可以打開程式管理員, 看看你的程式的CPU使用率是不是達到了100% 如果是, 而你又不是無限回圈, 那就再等等吧! 1.3G的檔案光是Copy也要不少時間咧! 更何況是還要運算 ^^ ===================引 用 rockhaword 文 章=================== 感謝回覆 用的大大的方法試過了 讀取小型檔案OK沒問題 但是讀取1.3G的大檔案就完全沒反應 還是感謝大大的回覆 ===================引 用 mephise 文 章=================== 文字檔就是必須循序讀取, 如果可以直接跳到第N行的話, 那資料庫也沒啥用了 檔案太大可以試試看這個方式: [code delphi] var f: TextFile str: String; begin AssignFile(f, 'C:\data.txt'); Reset(f); while not Eof(f) do begin Readln(f, str); // 把資料一次一行讀到 str, 然後再判斷 str 是不是你要的資料 end; end; [/code]
------
Mephise Chen 前興德工程師 |
GrandRURU
站務副站長 發表:240 回覆:1680 積分:1874 註冊:2005-06-21 發送簡訊給我 |
你可以利用TMemorystream來做分批讀取
可參考:http://www.delphigroups.info/3/8/442255.html 擷取一小部份程式碼 [code cpp] // Untested. TFileStream *FileStream; TMemoryStream *MemoryStream; FileStream = new TFileStream( "file.txt", fmOpenRead | fmShareDenyWrite ); MemoryStream = new TMemoryStream; MemoryStream->CopyFrom( FileStream, BytesToRead ); // Now use the contents of the memory stream and keep // doing CopyFrom to get new chunks until it returns 0, // for no bytes left. delete MemoryStream; delete FileStream; [/code] ===================引 用 rockhaword 文 章=================== 我想設計一個程式可以讀取大型文字檔.txt(檔案大小1.3G) 檔案總共有90多萬筆資料 一行一筆 每一筆的長度不一 不知道有沒有方法可以抓取想要的第 i 行的資料就好 目前測試了StringList的方法 但是因為檔案過大 會發生Out of memory [code delphi] if (OpenDialog1->Execute()){ TStringList *SLTmp = new TStringList(); SLTmp->LoadFromFile(OpenDialog1->FileName); for (int i=0; i < SLTmp->Count ; i ) { Memo1->Lines->Add(SLTmp->Strings[i]); }//end of while ( i < SLTmp->Count) delete SLTmp; } [/code] 不一定要一次讀完整個檔案 請問有沒有方法可以只抓取想要的第 i 行的資料就好
編輯記錄
GrandRURU 重新編輯於 2011-06-24 01:16:35, 註解 無‧
|
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
以Delphi提供個人做法,謹供參考
1.產生測試用的 DATA.TXT [code delphi] procedure TForm1.Button3Click(Sender: TObject); const FN_DATA='\DATA.TXT'; FM_PROGRESS='Count=%d, Progress=%.2f%%'; FM_FILEINFO='Count=%d, FileSize=%.0f'; var S: string; Count,J,K: Integer; DATA: TFileStream; BytesWritten,MAX_FILE_SIZE: Double; procedure ShowProgress; begin Label1.Caption := Format(FM_PROGRESS,[Count,BytesWritten*100/MAX_FILE_SIZE]); Label1.Update; end; begin MAX_FILE_SIZE := 1024*1024*10;//*1024*1024*1024*1.5; if not FileExists(FN_DATA) then begin DATA := TFileStream.Create(FN_DATA,fmCreate); try Count := 0; BytesWritten := 0; repeat K := Max(1,Random(50)); S := IntToStr(Count);//The No. for J := 0 to K do S := Format('%s,%d',[S,Random( MaxInt)]); S := S #$D #$A; BytesWritten := BytesWritten DATA.Write(PChar(S)^,Length(S)); Inc(Count); if Count mod 100 = 0 then ShowProgress; until BytesWritten>MAX_FILE_SIZE; ShowProgress; ShowMessage(Format(FM_FILEINFO,[Count,BytesWritten])); finally FreeAndNil(DATA); end; end; end; [/code] 2.建立索引檔 INDEX.DAT [code delphi] procedure TForm1.Button4Click(Sender: TObject); const FN_INDEX='\INDEX.DAT'; FN_DATA='\DATA.TXT'; FM_PROGRESS='Count=%d, Progress=%.2f%%'; type TIndexRec = packed record No: Integer; Pos: Int64; Len: Integer; end; var C: Char; I,St,BytesRead: Integer; L: TStringList; INDEX,DATA: TFileStream; r: TIndexRec; B: array[0..1024*64-1] of Char; begin if not FileExists(FN_INDEX) and FileExists(FN_DATA) then begin INDEX := TFileStream.Create(FN_INDEX,fmCreate); DATA := TFileStream.Create(FN_DATA,fmOpenRead); try C := #$0; FillChar(r,SizeOf(r),#$0); while DATA.Position St := DATA.Position; BytesRead := DATA.Read(B,SizeOf(B)); for I := 0 to BytesRead-1 do begin if (C=#$D) and (B[I]=#$A) then begin C := #$0; r.Len := St I-r.Pos 1; INDEX.Write(r,SizeOf(r)); Inc(r.No); r.Pos := St I 1; r.Len := 0; Continue; end; if (C=#$0) and (B[I]=#$D) then C := #$D; end; Label2.Caption := Format(FM_PROGRESS,[r.No,(DATA.Position 1)*100/DATA.Size]); Label2.Update; end; finally FreeAndNil(DATA); FreeAndNil(INDEX); end; end; //TestDump: INDEX.DAT if FileExists(FN_INDEX) then begin INDEX := TFileStream.Create(FN_INDEX,fmOpenRead); try INDEX.Position := 0; L := TStringList.Create; try while INDEX.Position L.Add(Format('%d, %d, %d',[r.No,r.Pos,r.Len])); ListBox1.Items.Text := L.Text; finally FreeAndNil(L); end; finally FreeAndNil(INDEX); end; end; end; [/code] 3. 利用 INDEX.DAT 對 DATA.TXT 做隨機讀取測試 [code delphi] procedure TForm1.Button5Click(Sender: TObject); const FN_INDEX='\INDEX.DAT'; FN_DATA='\DATA.TXT'; FM_OUTPUT='N=%d->No=%d->%s'; type TIndexRec = packed record No: Integer; Pos: Int64; Len: Integer; end; var S: string; I,N,Count: Integer; L: TStringList; INDEX,DATA: TFileStream; r: TIndexRec; begin if FileExists(FN_INDEX) and FileExists(FN_DATA) then begin INDEX := TFileStream.Create(FN_INDEX,fmOpenRead); DATA := TFileStream.Create(FN_DATA,fmOpenRead); L := TStringList.Create; try Count := INDEX.Size div SizeOf(TIndexRec); for I := 0 to 999 do begin N := Random(Count); INDEX.Position := SizeOf(TIndexRec)*N; if INDEX.Read(r,SizeOf(r))=SizeOf(r) then begin SetLength(S,r.Len); try DATA.Position := r.Pos; if DATA.Read(PChar(S)^,r.Len)=r.Len then begin L.Add(Format(FM_OUTPUT,[N,r.No,S])); end; finally S := ''; end; end; end; ListBox1.Items.Text := L.Text; finally FreeAndNil(L); FreeAndNil(DATA); FreeAndNil(INDEX); end; end; end; [/code] 4.刪除測試檔案 INDEX.DAT 及 DATA.TXT [code delphi] procedure TForm1.Button6Click(Sender: TObject); const FN_INDEX='\INDEX.DAT'; FN_DATA='\DATA.TXT'; begin if FileExists(FN_INDEX) then DeleteFile(FN_INDEX); if FileExists(FN_DATA) then DeleteFile(FN_DATA); end; [/code] |
rockhaword
一般會員 發表:3 回覆:5 積分:1 註冊:2011-05-30 發送簡訊給我 |
|
rockhaword
一般會員 發表:3 回覆:5 積分:1 註冊:2011-05-30 發送簡訊給我 |
你好 不好意思再打擾您 想問你一下 我用你的方法成功的讀取到大型文字檔 但有一個問題 如果短時間連續讀取會一直吃記憶體 最後造成Out of Memory 我用迴圈一直重複執行以下code [code delphi] N := i; INDEX.Position := SizeOf(TIndexRec)*N; if INDEX.Read(r,SizeOf(r))=SizeOf(r) then begin SetLength(S,r.Len); DATA.Position := r.Pos; if DATA.Read(PChar(S)^,r.Len)=r.Len then begin L.Add(Format(FM_OUTPUT,[N,r.No,S])); end; end; [/code]結果會記憶體使用量會急速上升 估計是S這個string吃掉記憶體 但是不知道該怎麼手動釋放 請問有辦法解決這個問題嗎 再次謝謝你喔 ===================引 用 jow 文 章=================== 以Delphi提供個人做法,謹供參考 1.產生測試用的 DATA.TXT [code delphi] procedure TForm1.Button3Click(Sender: TObject); const FN_DATA='\DATA.TXT'; FM_PROGRESS='Count=%d, Progress=%.2f%%'; FM_FILEINFO='Count=%d, FileSize=%.0f'; var S: string; Count,J,K: Integer; DATA: TFileStream; BytesWritten,MAX_FILE_SIZE: Double; procedure ShowProgress; begin Label1.Caption := Format(FM_PROGRESS,[Count,BytesWritten*100/MAX_FILE_SIZE]); Label1.Update; end; begin MAX_FILE_SIZE := 1024*1024*10;//*1024*1024*1024*1.5; if not FileExists(FN_DATA) then begin DATA := TFileStream.Create(FN_DATA,fmCreate); try Count := 0; BytesWritten := 0; repeat K := Max(1,Random(50)); S := IntToStr(Count);//The No. for J := 0 to K do S := Format('%s,%d',[S,Random( MaxInt)]); S := S #$D #$A; BytesWritten := BytesWritten DATA.Write(PChar(S)^,Length(S)); Inc(Count); if Count mod 100 = 0 then ShowProgress; until BytesWritten>MAX_FILE_SIZE; ShowProgress; ShowMessage(Format(FM_FILEINFO,[Count,BytesWritten])); finally FreeAndNil(DATA); end; end; end; [/code] 2.建立索引檔 INDEX.DAT [code delphi] procedure TForm1.Button4Click(Sender: TObject); const FN_INDEX='\INDEX.DAT'; FN_DATA='\DATA.TXT'; FM_PROGRESS='Count=%d, Progress=%.2f%%'; type TIndexRec = packed record No: Integer; Pos: Int64; Len: Integer; end; var C: Char; I,St,BytesRead: Integer; L: TStringList; INDEX,DATA: TFileStream; r: TIndexRec; B: array[0..1024*64-1] of Char; begin if not FileExists(FN_INDEX) and FileExists(FN_DATA) then begin INDEX := TFileStream.Create(FN_INDEX,fmCreate); DATA := TFileStream.Create(FN_DATA,fmOpenRead); try C := #$0; FillChar(r,SizeOf(r),#$0); while DATA.Position St := DATA.Position; BytesRead := DATA.Read(B,SizeOf(B)); for I := 0 to BytesRead-1 do begin if (C=#$D) and (B[I]=#$A) then begin C := #$0; r.Len := St I-r.Pos 1; INDEX.Write(r,SizeOf(r)); Inc(r.No); r.Pos := St I 1; r.Len := 0; Continue; end; if (C=#$0) and (B[I]=#$D) then C := #$D; end; Label2.Caption := Format(FM_PROGRESS,[r.No,(DATA.Position 1)*100/DATA.Size]); Label2.Update; end; finally FreeAndNil(DATA); FreeAndNil(INDEX); end; end; //TestDump: INDEX.DAT if FileExists(FN_INDEX) then begin INDEX := TFileStream.Create(FN_INDEX,fmOpenRead); try INDEX.Position := 0; L := TStringList.Create; try while INDEX.Position L.Add(Format('%d, %d, %d',[r.No,r.Pos,r.Len])); ListBox1.Items.Text := L.Text; finally FreeAndNil(L); end; finally FreeAndNil(INDEX); end; end; end; [/code] 3. 利用 INDEX.DAT 對 DATA.TXT 做隨機讀取測試 [code delphi] procedure TForm1.Button5Click(Sender: TObject); const FN_INDEX='\INDEX.DAT'; FN_DATA='\DATA.TXT'; FM_OUTPUT='N=%d->No=%d->%s'; type TIndexRec = packed record No: Integer; Pos: Int64; Len: Integer; end; var S: string; I,N,Count: Integer; L: TStringList; INDEX,DATA: TFileStream; r: TIndexRec; begin if FileExists(FN_INDEX) and FileExists(FN_DATA) then begin INDEX := TFileStream.Create(FN_INDEX,fmOpenRead); DATA := TFileStream.Create(FN_DATA,fmOpenRead); L := TStringList.Create; try Count := INDEX.Size div SizeOf(TIndexRec); for I := 0 to 999 do begin N := Random(Count); INDEX.Position := SizeOf(TIndexRec)*N; if INDEX.Read(r,SizeOf(r))=SizeOf(r) then begin SetLength(S,r.Len); try DATA.Position := r.Pos; if DATA.Read(PChar(S)^,r.Len)=r.Len then begin L.Add(Format(FM_OUTPUT,[N,r.No,S])); end; finally S := ''; end; end; end; ListBox1.Items.Text := L.Text; finally FreeAndNil(L); FreeAndNil(DATA); FreeAndNil(INDEX); end; end; end; [/code] 4.刪除測試檔案 INDEX.DAT 及 DATA.TXT [code delphi] procedure TForm1.Button6Click(Sender: TObject); const FN_INDEX='\INDEX.DAT'; FN_DATA='\DATA.TXT'; begin if FileExists(FN_INDEX) then DeleteFile(FN_INDEX); if FileExists(FN_DATA) then DeleteFile(FN_DATA); end; [/code] |
jow
尊榮會員 發表:66 回覆:751 積分:1253 註冊:2002-03-13 發送簡訊給我 |
將下列程式Mark起來,
應該是ListBox被塞爆了... ^_^ [code delphi] //TestDump: INDEX.DAT if FileExists(FN_INDEX) then begin INDEX := TFileStream.Create(FN_INDEX,fmOpenRead); try INDEX.Position := 0; L := TStringList.Create; try while INDEX.Position L.Add(Format('%d, %d, %d',[r.No,r.Pos,r.Len])); ListBox1.Items.Text := L.Text; finally FreeAndNil(L); end; finally FreeAndNil(INDEX); end; end; [/code] |
rockhaword
一般會員 發表:3 回覆:5 積分:1 註冊:2011-05-30 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |