| Autor |
Beitrag |
Biarchiv
      
Beiträge: 688
|
Verfasst: So 02.02.03 18:35
Hallo,
Habe folgendes Problem mit BlockRead and BlockWrite. Wolte nach bestimmten (rrrrrrr) in einer Datei suchen. Nach diesen Zeichencodes soll die Datei 30000 Bytes nach diesen String per Zufall mit welchen Zeichencodes gepatched werden ohne das die Datei größer werden darf.
Bur leider habe ich da einen Fehler drin.
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| fsFrom,fsTo : TFilestream; u,u1 : string; size1 : integer; f: file; l,l1 : Longint;
begin if not Fileexists(Edit1.Text) then begin showmessage('Can not open file.'); exit; end; u := 'rrrrrrr'; u1 := 'f'; AssignFile(f, Edit1.Text); Reset(f, 1); size1 := GetFileSize(Edit1.Text); for l := 3000 to size1 do begin Seek(f, l); BlockRead(f, u[1], Length(u)); if u = ''rrrrrrr'' then begin for l1 := 1 to 28000 do begin BlockWrite(f, u1[1], 1); end; end; end; CloseFile(f); |
Ist es auch möglich einen 1-100% Anzeige in einen Label1.Caption zu bekommen?
Danke..
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 03.02.03 09:55
| Biarchiv hat folgendes geschrieben: | | Bur leider habe ich da einen Fehler drin. |
Verrätst du auch, welchen? - Deine Beschreibung sagt was anderes aus als der von dir gepostete Code, und schon deshalb würde ich auf mehrere Fehler tippen. Nur, damit ich das hier verstehe:
| Zitat: | Wolte nach bestimmten (rrrrrrr) in einer Datei suchen. Nach diesen Zeichencodes
soll die Datei 30000 Bytes nach diesen String per Zufall mit welchen Zeichencodes
gepatched werden ohne das die Datei größer werden darf. |
Bis zum ersten Satz komme ich noch mit. Du suchst 7 R's ("rrrrrrr") in einer Datei. Wenn du die gefunden hast, dann ... hm, dein Text sagt: du willst 30.000 Bytes nach dem gefundenen String irgendwelche Zufallszeichen schreiben. Dein Code dagegen schreibt, gleich nach den 7 R's!, 28.000x das F in die Datei.
Tipps- Vielleicht solltest du dem String "u" vorher eine Länge (7, in dem Fall) zuweisen. Da ein String üblicherweise 255 Bytes besitzt (ShortString), ein langer String sogar noch mehr, würde es mich nicht wundern, wenn er mehr als 7 Bytes liest. Dass dann der Vergleich nicht mehr klappen kann, dürfte klar sein.
Handelt es sich tatsächlich um 7 R's? Dann benutz doch
Quelltext 1:
| u : array[0..6]of char; |
Das lässt sich ebenfalls gut einlesen und relativ einfach vergleichen:
Quelltext 1: 2:
| if(lstrcmp(u,'rrrrrrr') = 0) then ShowMessage('Die 7 R''s gefunden!'); |
- Bei BlockRead solltest du unbedingt den vierten Parameter nutzen. Der zeigt dir an, ob Fehler aufgetreten sind. Diese Integer-Variable enthält die Anzahl der eingelesenen Zeichen. Nur, wenn der Wert also deiner Puffergröße entspricht, solltest du weitermachen; andernfalls: nun, bei nur 4 oder 5 eingelesenen Zeichen besteht wohl kaum eine Chance 7 R's zu finden ... Oder?
- Die for-Schleife, mit der du 28.000x das F schreibst, ist überflüssig und langsam. BlockWrite kann in einem Rutsch 65k schreiben. Du kannst also wie folgt deklarieren:
Quelltext 1:
| u1 : array[0..27999]of char; |
sowie füllen und schreiben;
Quelltext 1: 2:
| fillchar(u1,sizeof(u1),'f'); BlockWrite(f,u1,sizeof(u1),iWrite); |
Die letzte Variable, "iWrite", dient auch bei BlockWrite der Fehlerkorrektur, wie ich es in Punkt #2 angedeutet habe.
- Wenn dein Code das korrekte Prinzip verdeutlicht (sprich: die 7 R's suchen und gleich danach 28.000 oder 30.000 Zufallszeichen schreiben), dann überleg mal, wie sinnvoll es ist, wieder zurückzuspringen und in dem gepatchten Teil wieder nach R's zu suchen? Ich rede davon:
Quelltext 1: 2: 3:
| for l := 3000 to size1 do begin Seek(f, l); |
Beispiel: Du springst an den Offset #3000 (1. Schleifenwert) und findest tatsächlich 7 R's. In dem Fall überschreibst du von Offset #3006 an die folgenden 28.000 Bytes mit F. Richtig? Dann kommt der nächste Schleifenwert (#3001). Du springst also zurück und suchst wieder nach 7 R's. Meinst du, du findest noch welche? - Kurz gesagt: mach doch einfach nach den überschriebenen 28.000 Bytes weiter.
|
|
Biarchiv 
      
Beiträge: 688
|
Verfasst: Mo 03.02.03 20:15
Hallo,
Kann statt rrrrrr auch gdfgdfg sein.
Ich wolte eine bestimmte Zeichenkette in einer Datei suchen und finden
und 32000 Bytes ab und mit dieser Zeichencodes zB mit ffh überschreiben.
Und dann weiter suchen bis Ende der File.
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 03.02.03 21:01
Na ja. Und Ideen, wie man´s richtig machen könnte und was man vermeiden sollte, habe ich dir ja genannt.
|
|
Biarchiv 
      
Beiträge: 688
|
Verfasst: Mi 05.02.03 20:38
Hallo,
Habe folgendes geschrieben und es Überschreibt die Dateienen nur hängt es sich nach dem
patch auf. Es reagiert nicht mehr. Ist die Endloss schleife falsch.
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| function Patch1(const FileName: TFileName): Boolean; var l,l1: Longint; u,u1: string; f: file; size1: integer; begin Result := False; u := 'testtest'; u1 := 'f'; size1 := GetFileSize(FileName); // size1 := size1 - 10; AssignFile(f, FileName); Reset(f, 1); l := 0; for l := 0 to size1 do begin Seek(f, l); BlockRead(f, u[1], Length(u)); if u = 'testtest' then begin for l1 := 0 to 28000 do begin BlockWrite(f,u1[1], Length(u1)); end; end; end; CloseFile(f); end; |
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Do 06.02.03 09:38
Irgendwie sehe ich keinen großen Unterschied zu deinem ersten Versuch.
Eine Endlosschleife sehe ich auch nicht.
Schau dir doch einfach mal das BlockRead/BlockWrite-Beispiel in der Hilfe an und benutze es als Anregung/Grundlage/Idee/...
|
|
Biarchiv 
      
Beiträge: 688
|
Verfasst: Do 06.02.03 10:26
Hallo,
Normal müßte es passen aber leider laut Delphi-Debuger erhängt sich das Proggi immer.
Vieleicht habe ich da irrgendo eine break oder so vergessen?
Oder sucht er dann immer wieder von Anfang an?
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Do 06.02.03 14:27
Eigentlich nicht, da du ja den Schleifenwert als Offset benutzt. Trotzdem ist dieser Weg zu umständlich und zu langsam. Nimm den hier (der sieht nur so lang aus, weil ich ihn gründlich kommentiert habe):
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52:
| var f : file; u : array[0..65535]of char; lPos : longint; iRead, iWrite : integer; begin {$I-} AssignFile(f,ExtractFilePath(paramstr(0)) + 'binary.dat'); ReSet(f,1);
if(IoResult = 0) then begin repeat // aktuelle Position merken, & 8 Bytes lesen lPos := filepos(f); BlockRead(f,u,8,iRead);
// waren es 8 Bytes? if(iRead = 8) then begin // ist es das Wort "testtest"? if(lstrcmp(u,'testtest') = 0) then begin // debugger ShowMessage(Format('"%s" at position %d',[u,lPos]));
// Puffer mit F's füllen, & 28.000 Stück schreiben fillchar (u,sizeof(u),'f'); BlockWrite(f,u,28000,iWrite); // Fehler beim Schreiben (evtl. Dateiende!); // Schleife verlassen if(iWrite <> 28000) then break;
// Puffer auf #0 zurücksetzen; sonst wird nicht // mehr korrekt weitergemacht fillchar (u,sizeof(u),#0); // das liegt an der Funktion "lstrcmp", die zwei PChars // (null-terminiert) miteinander vergleicht. Wenn der // Puffer aber lauter F's enthält, entsteht beim erneuten // Einlesen der Datei ein String wie // // testtestfffffffffffffffffffffffffff.... // // Folglich stimmt die Bedingung nicht mehr! end else // es war nicht das Wort "testtest"; // Suchposition um Eins erhöhen Seek(f,lPos+1); end; until(iRead = 0);
CloseFile(f); end; {$I+} end; |
Allerdings: das überschreibt nicht das gesuchte Wort (in dem Fall: "testtest"). Aber irgendwas musst du ja auch tun ... 
|
|
Biarchiv 
      
Beiträge: 688
|
Verfasst: Do 06.02.03 20:00
Hallo,
Danke an MathiasSimmack.
Danke für den Code.
Habe den Fehler gefunden nur leider geht dein Code auch nicht
wenn die Datei so 100 - 500 MB groß ist.
Was müßte ich da ändern um so große files patchen zu können
mit Deinen Code.
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 07.02.03 09:29
Es sollte schon gehen, es dauert nur etwas länger. 100 bis 500 meg wollen ja erst mal durchsucht werden.
Idee #1: Nach dem "Seek(f,lPos+1)" baust du ein "Application.ProcessMessages" ein. Damit bleibt deine Anwendung bedienbar, bzw. sie hängt sich nicht auf.
Die Anwendung hängt sich nicht wirklich auf! Wenn sie mit kleinen Dateien funktioniert, dann arbeitet sie auch große Brummer ab. Es fehlt in dem Fall nur an der Rückmeldung für Windows. Dadurch wird die Anwendung im TaskMan fälschlich (oder irreführend) als "reagiert nicht" dargestellt; aber wenn du in aller Ruhe abwartest, geht es tadellos.
Nun, wie auch immer: das "reagiert nicht"-Problem löst du mit dem Aufruf von "Application.ProcessMessages".
Idee #2: Progressbar einbauen. Die Dateigröße kannst du ja ermitteln; die aktuelle Position wird ermittelt; also - anzeigen lassen!
Und zur Laufzeit bitte die Buttons deaktivieren, damit der User zwar das Fenster rumschieben, aber nicht irgendwelche anderen Funktionen auslösen kann.
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 07.02.03 09:38
Ein Application.ProcessMessages bremst aber auch das Programm aus, da der Thread immer wieder in die Nachrichtenschleife geschickt wird, um zu kucken, ob was vorliegt.
Wenn große Dateien keine Ausnahme sind, würde ich das ganze in einen separaten Thread auslagern.
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Fr 07.02.03 09:56
Nur wenn man es zu oft aufruft!
Man könnte z.B. auch prüfen, ob die Datei einen bestimmten Schwellenwert (z.B. 10meg) überschreitet. In dem Fall sorgt man dafür, dass z.B. alle 20 oder 30 Durchläufe einmal "Application.ProcessMessages" aufgerufen wird.
|
|
|