Salve a tutti,
Sto cercando di realizzare una specie di parser in grado di leggere un file di testo una riga per volta e confrontarlo con il contenuto di un altro file di testo contenente alcune regole. Quando viene trovato il match della riga con una regola viene scritto su un file xml.
Per file piccoli funziona ed è anche abbastanza veloce. La parte di codice che fa il lavoro da me descritto è la seguente:
procedure TGUI_Parser.ManeggiaLog(const txt: String);
var myFile : TextFile;
myStringa, myOre, myMinuti, mySecondi, mySubStr: Ansistring;
m: integer;
FlagCapt, FlagNew, FlagReal, FlagAlr: boolean;
begin
AssignFile(myFile,txt);
Reset(myFile);
Visualizzatore.Append('Leggo Log File: '+txt);
StringaCapt_o :='';
StringaId_o :='';
RealTime_o := '';
CpuTime_o := '';
FlagCapt := False;
FlagNew := False;
FlagReal := False;
SetLength(StringaVett,3500000);
k:=0;
while not Eof(myFile) do
begin
FlagCapt := False;
FlagAlr := False;
StringaCapt_o:=MyDeclare.StringaCapt;
StringaId_o:=MyDeclare.StringaId;
RealTime_o:=MyDeclare.RealTime;
CpuTime_o:=MyDeclare.CpuTime;
ReadLn(myFile,myStringa);
...
end;
Purtroppo mi può capitare di maneggiare file di qualche centinaio di MB e in questo caso sto cercando di utilizzare il Filestream per fare lo stesso lavoro ma sembra che per come l'ho implementato io (codice di seguito) non riesca a leggere le righe allo stesso modo.
procedure TGUI_Parser.ManeggiaLog(const txt: String);
var //myFile : TextFile;
Reader : TFileStream;
myStringa, myOre, myMinuti, mySecondi, mySubStr: Ansistring;
m,index,bufferleng: integer;
FlagCapt, FlagNew, FlagReal, FlagAlr: boolean;
begin
//AssignFile(myFile,txt);
// Reset(myFile);
Visualizzatore.Append('Leggo Log File: '+txt);
StringaCapt_o :='';
StringaId_o :='';
RealTime_o := '';
CpuTime_o := '';
FlagCapt := False;
FlagNew := False;
FlagReal := False;
bufferleng := 32768;
k:=0;
SetLength(StringaVett,3500000);
// while not Eof(myFile) do
try
Reader := TFileStream.Create(txt,fmOpenRead);
FlagCapt := False;
FlagAlr := False;
StringaCapt_o:=MyDeclare.StringaCapt;
StringaId_o:=MyDeclare.StringaId;
RealTime_o:=MyDeclare.RealTime;
CpuTime_o:=MyDeclare.CpuTime;
Index := 0;
MyStringa := '';
Reader.Seek(Index,soFromBeginning);
SetLength(MyStringa,bufferleng);
Reader.Read(MyStringa,Index);
...
Index := Index + bufferleng;
finally
Reader.Free;
end;
Non riesco a capire cosa ci sia che non vada bene. Potete aiutarmi per favore?
Grazie mille.
Francesco
Reader.Read(MyStringa,Index);
Prova
Reader.Read(MyStringa[1],Index);
Dimmi se funziona ;)
Allora mi sfugge il problema ...
Leggi la stringa sempre alla stessa posizione....
SetLength(MyStringa,bufferleng);
Reader.Read(MyStringa,Index);
A occhio e crocie quello che leggi è una parte del file.
Se leggi 3 volte, leggi nella posizinoe 3 blocchi del file.
Quindi :
1) Leggi tutto lo stream in un colpo solo.
2) Sposti l'indice di scrittura della stringa.
Ma forse non ho capito il problema e sto andando a margherite...
Stilgar
Ehm, scusami Stilgar, ma non è quello che stavo facendo io?
Nel frattempo ho cambiato qualche riga, ma l'effetto è sempre lo stesso.
Riscrivo il codice come nella mia ultima modifica. Grazie di nuovo per la tua disponibilità e la tua gentilezza.
procedure TGUI_Parser.ManeggiaLog(const txt: String);
var //myFile : TextFile;
Reader : TFileStream;
myStringa, myOre, myMinuti, mySecondi, mySubStr: Ansistring;
m,index,bufferleng: integer;
FlagCapt, FlagNew, FlagReal, FlagAlr: boolean;
begin
//AssignFile(myFile,txt);
// Reset(myFile);
Visualizzatore.Append('Leggo Log File: '+txt);
StringaCapt_o :='';
StringaId_o :='';
RealTime_o := '';
CpuTime_o := '';
FlagCapt := False;
FlagNew := False;
FlagReal := False;
bufferleng := 32768;
k:=0;
SetLength(StringaVett,3500000);
Index := 0;
try
Reader := TFileStream.Create(txt,fmOpenRead);
FlagCapt := False;
FlagAlr := False;
StringaCapt_o:=MyDeclare.StringaCapt;
StringaId_o:=MyDeclare.StringaId;
RealTime_o:=MyDeclare.RealTime;
CpuTime_o:=MyDeclare.CpuTime;
MyStringa := '';
while Index < Reader.Size do
begin
Reader.Seek(Index,soFromBeginning);
Index := Index + Bufferleng;
SetLength(MyStringa,bufferleng);
Reader.Read(MyStringa,bufferleng);
...
finally
Reader.Free;
end;
Frandell... questo è solo un ciclo di lettura ... vedendo questo codice mi viene da pensare che leggi e parsi.
Quello che dicevo io era più del tipo:
procedure parse(const s : TStream);
var
c : Char;
accumulo : String;
begin
while s.read(C,SizeOf(C)) < SizeOf(C) do
begin
if C <> #32 then { o #13 o #10 o altri separatori di comodo }
accumulo := accumulo +C;
else
begin
{ qualche cosa legata al parser }
end;
end;
end;
Tu leggi un blocco e poi lo interpreti.
Stilgar
Ciao e scusate di nuovo.
Come da suggerimento di Stilgar ho provato a modificare il codice in questo modo:
procedure TGUI_Parser.ManeggiaLog(const txt: String);
var //myFile : TextFile;
Reader : TFileStream;
myStringa, myOre, myMinuti, mySecondi, mySubStr: Ansistring;
c : char;
m, Index: integer;
//,index,bufferleng
FlagCapt, FlagNew, FlagReal, FlagAlr: boolean;
begin
//AssignFile(myFile,txt);
// Reset(myFile);
Visualizzatore.Append('Leggo Log File: '+txt);
StringaCapt_o :='';
StringaId_o :='';
RealTime_o := '0';
CpuTime_o := '0';
FlagCapt := False;
FlagNew := False;
FlagReal := False;
//bufferleng := 32768;
k:=0;
SetLength(StringaVett,3500000);
Index := 0;
try
Reader := TFileStream.Create(txt,fmOpenRead);
FlagCapt := False;
FlagAlr := False;
StringaCapt_o:=MyDeclare.StringaCapt;
StringaId_o:=MyDeclare.StringaId;
RealTime_o:=MyDeclare.RealTime;
CpuTime_o:=MyDeclare.CpuTime;
myStringa := '';
while Index < Reader.Size do
begin
Reader.read(c,sizeof(c));
Visualizzatore.Append('Valore di C '+c);
if (C <> #13) or (C <> #10) then
begin
myStringa := myStringa + C;
...
myStringa := ''; //per reinizializzare la stringa una volta andato a capo
end;
finally
Reader.Free;
end;
L'ho lanciato da due ore e mezza ed è ancora in esecuzione (ammesso che vada bene). Speravo di potermela cavare con molto meno. Potete per favore suggerirmi qualcosa per renderlo più veloce?
Grazie in anticipo e scusatemi ancora.
Fra
Visualizzatore.Append('Valore di C '+c);
Visualizzatore .... cosa è?
Stilgar
PS:
Index????? Cosa è ??
Lo sposti?
Grazie ancora per i validi suggerimenti, Stilgar.
Il codice è diventato questo:
procedure TGUI_Parser.ManeggiaLog(const txt: String);
var
Reader : TFileStream;
myStringa, myOre, myMinuti, mySecondi, mySubStr: Ansistring;
c : char;
m, Index: integer;
FlagCapt, FlagNew, FlagReal, FlagAlr: boolean;
begin
Visualizzatore.Append('Leggo Log File: '+txt);
StringaCapt_o :='';
StringaId_o :='';
RealTime_o := '0';
CpuTime_o := '0';
FlagCapt := False;
FlagNew := False;
FlagReal := False;
k:=0;
SetLength(StringaVett,3500000);
Index := 0;
try
Reader := TFileStream.Create(txt,fmOpenRead);
FlagCapt := False;
FlagAlr := False;
StringaCapt_o:=MyDeclare.StringaCapt;
StringaId_o:=MyDeclare.StringaId;
RealTime_o:=MyDeclare.RealTime;
CpuTime_o:=MyDeclare.CpuTime;
myStringa := '';
while Index < Reader.Size do
begin
Reader.read(c,sizeof(c));
if (C <> #13) or (C <> #10) then
begin
myStringa := myStringa + C;
...
end;
myStringa := '';
Index := Index + Sizeof(c);
Reader.Seek(Index,soFromBeginning);
end;
finally
Reader.Free;
end;
If Index mod 2000 = 0 then
Application.ProcessMessages;
end;
Purtroppo è ancora un po' troppo lento... :(
procedure TGUI_Parser.ManeggiaLog(const txt: String);
var
Reader : TFileStream;
myStringa, myOre, myMinuti, mySecondi, mySubStr: Ansistring;
c : char;
m, Index: integer;
FlagCapt, FlagNew, FlagReal, FlagAlr: boolean;
begin
Visualizzatore.Append('Leggo Log File: '+txt);
StringaCapt_o :='';
StringaId_o :='';
RealTime_o := '0';
CpuTime_o := '0';
FlagCapt := False;
FlagNew := False;
FlagReal := False;
k:=0;
SetLength(StringaVett,3500000);
Index := 0;
try
Reader := TFileStream.Create(txt,fmOpenRead);
FlagCapt := False;
FlagAlr := False;
StringaCapt_o:=MyDeclare.StringaCapt;
StringaId_o:=MyDeclare.StringaId;
RealTime_o:=MyDeclare.RealTime;
CpuTime_o:=MyDeclare.CpuTime;
myStringa := '';
while Index < Reader.Size do
begin
Reader.read(c,sizeof(c));
if (C <> #13) or (C <> #10) then
begin
myStringa := myStringa + C;
...
end;
myStringa := '';
Index := Index + Sizeof(c);
// Reader.Seek(Index,soFromBeginning); inutile se non dannoso ... sei già alla posizione index dall'inizio dello stream.
If Index mod 2000 = 0 then
Application.ProcessMessages;
end;
finally
Reader.Free;
end;
end;
Prova a vedere ...
interface
function currentTimeMillis: int64;
implementation
type
TOS = record
javaTimeMillis: function: int64;
javaTimeNanos: function: int64;
end;
var
OS: TOS;
{$IFDEF WINDOWS}
function jlong_from(h, l: word): int64;
var
R: Int64Rec;
begin
R.Lo := l;
R.Hi := h;
Result := int64(r);
end;
function offset(): int64;
var
java_origin: SYSTEMTIME;
jot: FILETIME;
begin
java_origin.wYear := 1970;
java_origin.wMonth := 1;
java_origin.wDayOfWeek := 0; // ignored
java_origin.wDay := 1;
java_origin.wHour := 0;
java_origin.wMinute := 0;
java_origin.wSecond := 0;
java_origin.wMilliseconds := 0;
FillChar(jot, SizeOF(jot), 0);
SystemTimeToFileTime(java_origin, jot);
Result := jlong_from(jot.dwHighDateTime, jot.dwLowDateTime);
end;
function windows_to_java_time(wt: TFILETIME): int64;
begin
Result := jlong_from(wt.dwHighDateTime, wt.dwLowDateTime);
Result := (Result - offset()) div 10000;
end;
function javaTimeMillis_md: int64;
var
wt: TFILETIME;
begin
GetSystemTimeAsFileTime(wt);
Result := windows_to_java_time(wt);
end;
const
NANOS_PER_SEC = 1000000000;
NANOS_PER_MILLISEC = 1000000;
var
has_performance_count: int = 0;
first_filetime: int64;
initial_performance_count: int64;
performance_frequency: int64;
function javaTimeNanos_md(): int64;
var
current_count: TLargeInteger;
current: double;
freq: double;
begin
Result := 0;
current_count := 0;
QueryPerformanceCounter(current_count);
current := current_count;
freq := performance_frequency;
Result := Trunc((current / freq) * NANOS_PER_SEC);
end;
procedure initialize_performance_counter();
var
Count: TLargeInteger;
wt: TFILETIME;
begin
if (QueryPerformanceFrequency(Count)) then
begin
has_performance_count := 1;
performance_frequency := Count;
QueryPerformanceCounter(Count);
initial_performance_count := Count;
end
else
begin
has_performance_count := 0;
GetSystemTimeAsFileTime(wt);
first_filetime := jlong_from(wt.dwHighDateTime, wt.dwLowDateTime);
end;
end;
{$ENDIF}
function currentTimeMillis: int64;
begin
Result := OS.javaTimeMillis();
end;
initialization
initialize_performance_counter;
os.javaTimeMillis := @javaTimeMillis_md;
os.javaTimeNanos := @javaTimeNanos_md;
usa questo pezzo di codice per prendere i tempi ;)