Problem mit FindallFiles

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
allesquarks
Beiträge: 4
Registriert: Mi 11. Nov 2009, 19:38

Problem mit FindallFiles

Beitrag von allesquarks »

Hallo ich habe folgendes Problem: Ich will mit einem Konsolenprogramm auf Textfiles eine bestimmte Operation anwenden und suche mir über Findallfiles alle in einem Ordner evt. rekursiv raus. Das hat in einem Projekt wunderbar funktioniert. Nun sitze ich an einem sehr ähnlichen, wo ich viel wiederverwenden wollte und bei findallfiles wird mir nun immer eine exeption geworfen, obwohl der Aufruf absolut identisch ist zum ersten Projekt. Konkret geht bei folgender code Zeile was schief:
[

Code: Alles auswählen

myfiles:=Findallfiles(SourceDir,'',true);
. Der Fehler entsteht beim Konstruktor von TListfileSearcher, die Fehlermeldung ist: "Project raised Exception class 'External: SIGSEGV'." Danach folgt ein Fenster Ausführung angehalten: Adresse $0040B6D0 und Prozedur: SYSTEM_ALLOC_OSCHUNK$LONGINT$LONGINT$$POINTER

Falls das jemand ausprobieren möchte: Hier ist der Quelltext. Ist ja nur die Hauptunit. Die betreffende Codezeile ist 446. Damit es funktioniert muss man noch unter Projekt -> Projekteinstellungen die LCL als Package einbinden. In der Vorschau ist unten bei DirSep der Backspace kaputt, falls das mit dem Copy und pasten nicht funktioniert. Achso man muss als erstes Argument einen Ordnerpfad übergeben und als zweiten den Pfad zu einem Textfile, in dem folgendes steht:

Code: Alles auswählen

23.02.1975 12:00:00 240
23.02.2075 12:34:56 140

Code: Alles auswählen

program syncnorm;
 
{$mode objfpc}{$H+}
 
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp,
  { you can add units after this }
  fileutil,dateutils;
 
type
 
  TIntarray = array of integer;
  TDoublearray = array of double;
  TStringarray = array of string;
  TEnergy = (Ebin,Ekin);
  TPlace = (Berlin,Hamburg);
 
  TTimePoint = record
    time:TDateTime;
    intensity:double;
  end;
 
  TTimePeriod = array[0..1] of TTimePoint;
  TTimes = array of TTimePeriod;
 
  { TSpektraNormalizer }
 
  TSpektraNormalizer = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    timearray:TTimes;
    dorename:boolean;
    dirsep:char;
    basepath,newbasepath:string;
 
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
 
    function ReadTimeFile(filename: string):boolean;
    function ProcessDirectory(relpathname: string):boolean;
    procedure provideDestDir(relpath:string);
    function ProcessFile(relpathname:string):boolean;
    function calculatenormfaktor(datetime:TDatetime;sweeps:integer):double;
    procedure normalize(var yarray:TDoublearray;normfaktor:double);
  end;
 
{ TSpektraNormalizer }
 
 
//Falls term nicht in line vorhanden ist ist das Ergebnis Null
function strcmp(line1,term:string):integer;
var i,a:integer;identical:boolean;line:string;
begin
  line:=lowercase(line1);
  result:=-1;
  for i:=1 to length(line)-length(term)+1 do
  begin
    if line[i]=term[1] then
    begin
      //nur vorläufig
      identical:=true;
      for a:=2 to length(term) do
      begin
        if line[i-1+a]<>term[a] then
        begin
          identical:=false;
          break;
        end;
      end;
      if identical then
      begin
        result:=i;
        break;
      end;
    end;
  end;
end;
 
function parseline(line:string;var xwert,ywert:double):boolean;
var i,a,beginfirst,endfirst,beginsecond,endsecond:integer;
begin
     //Nummer neun ist das Tabulatorsteuerzeichen
     result:=false;
     beginfirst:=1;
     beginsecond:=1;
     for i:=1 to length(line) do
     begin
       if not (line[i] in [' ',#9]) then
       begin
         beginfirst:=i;
         break;
       end;
     end;
     //first number
     for i:=beginfirst+1 to length(line) do
     begin
       //E für exponentielle Schreibweise
       if not (line[i] in ['0'..'9','.',',','-','+','E',' ',#9]) then
       begin
         //bedeutet diese Zeile beinhaltet nicht nur Messdaten
         result:=false;
         exit;
       end;
       if line[i] in [' ',#9] then
       begin
         endfirst:=i;
         xwert:=strtofloat(copy(line,beginfirst,endfirst-beginfirst));
         //und den nächsten Anfag finden
         for a:=i+1 to length(line) do
         begin
           if not(line[a] in [' ',#9]) then
           begin
             beginsecond:=a;
             break;
           end;
         end;
         break;
       end;
     end;
 
     if beginsecond=length(line) then
     begin
       ywert:=strtofloat(copy(line,beginsecond,1));
       result:=true;
       exit;
     end;
 
     //second number
     for i:=beginsecond+1 to length(line) do
     begin
          //E für exponentielle Schreibweise
          if not (line[i] in ['0'..'9','.',',','-','+','E',' ',#9]) then
          begin
               result:=false;
               exit;
          end;
          if (line[i] in [' ',#9]) or (i=length(line)) then
          begin
               endsecond:=i;
               if i=length(line) then
               begin
                 inc(endsecond);
               end;
               ywert:=strtofloat(copy(line,beginsecond,endsecond-beginsecond));
               //nur wenn beide Zahlen gefunden wurden wird die Funktion true
               result:=true;
               break;
          end;
     end;
end;
 
function assumesize(filename:string):integer;
begin
  //muss noch dynamisch anhand der Dateigröße geschätzt werden
  result:=round(Filesize(filename)/8)+1; //also jede Zeile hat im Mittel acht ascii Zeichen
end;
 
 
function WriteFile(filename:string;xarray,yarray:TDoublearray):boolean;
var i:integer;datfile:textfile;
begin
  result:=false;
  try
    assignfile(datfile,filename); //datei öffnen, dir = dateipfad
    rewrite(datfile); //'f' zurücksetzen
 
    for i:=0 to length(xarray)-1 do
    begin
      writeln(datfile,xarray[i]:7:6,'  ',yarray[i]:7:6); //zeile auslesen und in 'zeile' speichern
    end;
    result:=true;//falls eine Excpetion dann direkt zu finally ohne true zu werden
  finally
    //Rewrite(TextDatei); //Datei erstellen
    closefile(datfile);
  end;
end;
 
function TSpektranormalizer.ReadTimeFile(filename: string):boolean;
var datfile:Textfile;worktext,olddateformat,oldtimeformat:string;
    i,a,assumedsize,valuepair:integer;
    intensity:double;datetime:TDateTime;
begin
  if filename='' then
  begin
    writeln('No Time File has been passed');
    Halt;
  end;
  olddateformat:=shortdateformat;
  oldtimeformat:=longtimeformat;
  shortdateformat:='dd.mm.yyyy';
  longtimeformat:='hh:nn:ss';
 
  result:=false;
  try
    assignfile(datfile,filename); //datei öffnen, dir = dateipfad
    reset(datfile); //'f' zurücksetzen
 
    //Arraygröße schätzen und setzen
    assumedsize:=assumesize(filename);
    setlength(timearray,assumedsize);
 
    i:=0;
    a:=0;
    while not eof(datfile) do //weil das dokument ncoh nciht zu ende ist tue
    begin
      inc(a);
      ReadLn(datfile,worktext); //zeile auslesen und in 'zeile' speichern
 
      i:=length(worktext)-1;
      //zweites Argument Zeit
      while i>=1 do
      begin
        if worktext[i]=' ' then
        begin
          intensity:=strtofloat(copy(worktext,i+1,length(worktext)-i));
          dec(i);
          while worktext[i]=' ' do
          begin
            dec(i);
          end;
          break;
        end;
        dec(i);
      end;
      //erstes Argument ist im Rest
      datetime:=strtodatetime(copy(worktext,1,i));
 
      valuepair:=a mod 2;
      if valuepair<>0 then
      begin
        timearray[valuepair-1][1].time:=datetime;
        timearray[valuepair-1][1].intensity:=intensity;
      end else begin
        timearray[valuepair-1][0].time:=datetime;
        timearray[valuepair-1][0].intensity:=intensity;
      end;
    end;
 
    setlength(timearray,valuepair);
    result:=true;
  finally
    closefile(datfile);
    shortdateformat:=olddateformat;
    longtimeformat:=oldtimeformat;
  end;
end;
 
function ReadFile(filename: string;var xarray,yarray:TDoublearray;datetime:TDateTime;sweeps:integer;regionname:string):boolean;
var datfile:Textfile;worktext:string;i,assumedsize:integer;
    date:TDatetime;time:TDatetime;
begin
  result:=false;
  try
    assignfile(datfile,filename); //datei öffnen, dir = dateipfad
    reset(datfile); //'f' zurücksetzen
 
    //Arraygröße schätzen und setzen
    assumedsize:=assumesize(filename);
    setlength(xarray,assumedsize);
    setlength(yarray,assumedsize);
 
    i:=0;
    while not eof(datfile) do //weil das dokument ncoh nciht zu ende ist tue
    begin
      ReadLn(datfile,worktext); //zeile auslesen und in 'zeile' speichern
 
      if strcmp(worktext,'date')<>-1 then
      begin
        date:=strtodate(copy(worktext,6,length(worktext)-5));
      end else
      if strcmp(worktext,'time')<>-1 then
      begin
        time:=strtotime(copy(worktext,6,length(worktext)-5));
      end else
      if strcmp(worktext,'region name')<>-1 then
      begin
        regionname:=copy(worktext,13,length(worktext)-12);
      end else
      if strcmp(worktext,'number of sweeps')<>-1 then
      begin
        sweeps:=strtoint(copy(worktext,18,length(worktext)-17));
        break;
      end;
    end;
 
    datetime:=date+time;
 
    i:=0;
    while not eof(datfile) do //weil das dokument ncoh nciht zu ende ist tue
    begin
      ReadLn(datfile,worktext); //zeile auslesen und in 'zeile' speichern
      if parseline(worktext,xarray[i],yarray[i]) then
      begin
        inc(i);
      end else begin
 
      end;
    end;
 
    setlength(xarray,i);
    setlength(yarray,i);
    result:=true;
  finally
    closefile(datfile);
  end;
end;
 
 
procedure TSpektraNormalizer.provideDestDir(relpath:string);
var a:integer;
begin
//Schauen ob relpath noch ORdnerteile enthält und diese ggf anlegen
  for a:=length(relpath) downto 1 do
  begin
    if relpath[a]=DirSep then
    begin
      if not(DirectoryExists(newbasepath+copy(relpath,1,a))) then
      begin
        provideDestDir(copy(relpath,1,a-1));
        CreateDirUTF8(newbasepath+copy(relpath,1,a));
      end;
      break;
    end;
  end;
end;
 
procedure appendregionname(var filename,regionname:string);
var i:integer;
begin
  for i:=length(filename) downto 1 do
  begin
    if filename[i]='.' then
    begin
      insert(regionname,filename,i-1);
      exit;
    end;
  end;
end;
 
function TSpektraNormalizer.calculatenormfaktor(datetime:TDatetime;sweeps:integer):double;
begin
 
end;
 
 
function TSpektraNormalizer.ProcessFile(relpathname:string):boolean;
var DestFile,SourceFile:string;
    xarray,yarray:TDoublearray;
    normfaktor:double;
    successread,successwrite:boolean;
    datetime:TDatetime;regionname:string;sweeps:integer;
begin
 
  DestFile:=newbasepath+relpathname;
 
  SourceFile:=basepath+relpathname;
 
        //entry = readdir(VZ);
        //if (entry != NULL) {
 
 
 
	  //lowercase(entry->d_name);
	  //secogefunden = (char*)strstr(entry->d_name,suchseco);
	  //datgefunden = (char*) strstr(entry->d_name,suchdat);
	 // if ((secogefunden != NULL) && (datgefunden != NULL)) {
  writeln('Prozessiere Datfile mit Namen: ');
  writeln(SourceFile);
	    //Länge herausfinden
	    //stat(origname, &attribut);
	    //lines=attribut.st_size*0.2;
 
  successread:=ReadFile(SourceFile,xarray,yarray,datetime,sweeps,regionname);
 
  if dorename then
  begin
    appendregionname(destfile,regionname);
  end;
 
  normfaktor:=calculatenormfaktor(datetime,sweeps);
 
  normalize(yarray,normfaktor);
 
 
 
  successwrite:=WriteFile(DestFile,xarray,yarray);
 
  if (successread and successwrite) then
  begin
    writeln('Die Datei wurde erfolgreich verarbeitet');
    writeln('');
  end else begin
    writeln('Die Datei wurde NICHT erfolgreich verarbeitet');
    writeln('');
  end;
end;
 
procedure expandsearchmask(var mask:string;var searchterms:TStringarray);
var i,ending:integer;wildcard:string;
begin
  //schon einmal die Endwildcard anhängen
  wildcard:='*';
  if mask[length(mask)]<>'*' then
  begin
    mask:=mask+'*';
  end;
  ending:=length(mask);
 
  for i:=length(mask) downto 1 do
  begin
    if mask[i]=';' then
    begin
      setlength(searchterms,length(searchterms)+1);
      searchterms[length(searchterms)-1]:=copy(mask,i+1,ending-i-1);
      ending:=i;
 
      insert(wildcard,mask,i+1);
      insert(wildcard,mask,i);
    end;
  end;
  setlength(searchterms,length(searchterms)+1);
  searchterms[length(searchterms)-1]:=copy(mask,1,ending-1);
  insert(wildcard,mask,1);
end;
 
function TSpektraNormalizer.ProcessDirectory(relpathname: string):boolean;
var SourceDir,DestDir,currentfile,relpath,purefilename,filesearchmask,mask:string;myfiles:TStringlist;
    successread,successwrite,pathisdestination,masknotmatched,dorecursive:boolean;
    i,a,test:integer;
    searchterms:TStringarray;
begin
  //SourceDir:=opendir(pathname);
  DestDir:=newbasepath+relpathname;
  SourceDir:=basepath+relpathname;
 
  //hier werden die direkt die Dateien rekursiv oder nicht gesucht.
  //mask:='.txt;.dat';
  //expandsearchmask(mask,searchterms);
  //myfiles:=Findallfiles('C:\test\','',true);
  //dorecursive:=true;
  myfiles:=Findallfiles(SourceDir,'',true);//letzter Parameter ist subdirs
 
  //Sicherhaitsabfragen
  if not(CreateDirUTF8(DestDir)) then
  begin
    writeln('Warning: The Destination Folder ',relpathname,' does exist.');
    writeln('Files will be overwritten');
  end;
 
  if not (Directoryiswritable(DestDir)) then
  begin
    writeln('The Folder is not writable');
    halt;
  end;
 
  //Eigentliche Schleife (nur ein File wir im Hauptprogramm abgefangen
  //hier nur Unterscheidung zwishcen rekursiv oder nicht
 
  writeln;
  writeln;
 
  for i:=0 to myfiles.count-1 do
  begin
    pathisdestination:=false;
 
    currentfile:=myfiles.Strings[i];
    relpath:=createRelativePath(currentfile,basepath);
       //Im ersten Teil der relativen Pfadangabe nach dem Zielordner suchen
    //Da ja die Zieldateien nicht auch noch verarbeitet werden sollen
    //Endlosschleife
    for a:=1 to length(relpath) do
    begin
      if relpath[a]=DirSep then
      begin
        if strcmp(copy(relpath,1,a-1),'corr')<>-1 then
        begin
          pathisdestination:=true;
        end;
        break;
      end;
    end;
    if pathisdestination then
    begin
      continue;
    end;
 
    Purefilename:=ExtractFileNameOnly(relpath);
    masknotmatched:=false;
    for a:=0 to length(searchterms)-1 do
    begin
      if strcmp(Purefilename,searchterms[a])=-1 then
      begin
        masknotmatched:=true;
        break;
      end;
    end;
 
    if masknotmatched then
    begin
      continue;
    end;
 
    provideDestDir(relpath);
 
    processfile(relpath);
 
  end;
end;
 
procedure TSpektranormalizer.normalize(var yarray:TDoublearray;normfaktor:double);
var i:integer;skalefaktor:double;
begin
  if normfaktor=0 then
  begin
    writeln('Achtung ein falscher Normfaktor wurde übergeben');
  end else begin
    skalefaktor:=1/normfaktor;
    for i:=0 to length(yarray)-1 do
    begin
      yarray[i]:=yarray[i]*skalefaktor;
    end;
  end;
end;
 
 
procedure TSpektraNormalizer.DoRun;
var
  ErrorMsg,MyShortOptions,teststring,relpathname,timefilepath: String;
  parametercount,argumentcount,optioncount:integer;
const
  MyLongOptions:array [0..1] of string = ('help','rename');
begin
  MyShortOptions:='hr';//oswE:F:V:';
  self.CaseSensitiveOptions:=false;
 
  // quick check parameters
  ErrorMsg:=CheckOptions(MyShortOptions,MyLongOptions);
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Halt;
  end;
  writeln(getparams(0));
 
  parametercount:=GetParamCount;
  optioncount:=0;
 
  // parse parameters
  if HasOption('h','help') then begin
    WriteHelp;
    inc(optioncount);
    Halt;
  end;
 
  if HasOption('r','rename') then
  begin
    inc(optioncount);
  end;
  dorename:=HasOption('rename');
 
  { Argumente parsen vorher waren es Optionen }
  argumentcount:=parametercount-optioncount;
  if argumentcount=0 then
  begin
    halt;
  end else begin
    if argumentcount>2 then
    begin
      writeln('Too many arguments have been passed!');
      halt;
    end else begin
      basepath:=Getparams(optioncount+1);
      if not(DirectoryExists(basepath)) then
      begin
        writeln('Es wurde kein Verzeichnis übergeben');
        halt;
      end else begin
        writeln(basepath);
        //Add Backspace if necessary
        if basepath[length(basepath)]<>Dirsep then
        begin
          basepath:=basepath+DirSep;
        end;
        newbasepath:=basepath+'corr'+DirSep;
 
        if argumentcount=2 then
        begin
          timefilepath:=lowercase(Getparams(optioncount+2));
        end else begin
          writeln('No file with pairs of time intensity values has been passed');
        end;
      end;
    end;
  end;
 
  if not(Readtimefile(timefilepath)) then
  begin
    writeln('The File with time <-> intensity mapping is invalid');
  end;
 
 
 
  { add your program here }
 
  writeln;
  writeln;
 
  processDirectory('');
 
 
  // stop program loop
  Terminate;
end;
 
constructor TSpektraNormalizer.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
 
  DirSep:='\';
end;
 
destructor TSpektraNormalizer.Destroy;
begin
  inherited Destroy;
end;
 
procedure TSpektraNormalizer.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ',ExeName,' -h');
end;
 
var
  Application: TSpektraNormalizer;
begin
  Application:=TSpektraNormalizer.Create(nil);
  Application.Title:='SpektraNormalizer';
  Application.Run;
  Application.Free;
end.

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Problem mit FindallFiles

Beitrag von theo »

Wäre nett, wenn du das ein anderes Mal auf's wesentliche kürzen könntest.

Ich tippe mal beim drüberfliegen darauf, dass du dein

myfiles:TStringlist;

vor dem Gebrauch nicht created hast.

allesquarks
Beiträge: 4
Registriert: Mi 11. Nov 2009, 19:38

Re: Problem mit FindallFiles

Beitrag von allesquarks »

Naja das createn macht Findallfiles eigentlich selber, in dem ersten Projekt hats ja auch ohne createn funktioniert. Ich weiß selber auch, dass das sehr lang ist, hab ich auch nur gemacht, damit ihr das reproduzieren könnt, denke nämlich nicht, dass es so eine einfache Lösung gibt.
For the Record ein TStringlist.create direkt davor bringt keine Abhilfe.

Benutzeravatar
theo
Beiträge: 10869
Registriert: Mo 11. Sep 2006, 19:01

Re: Problem mit FindallFiles

Beitrag von theo »

allesquarks hat geschrieben:Naja das createn macht Findallfiles eigentlich selber, in dem ersten Projekt hats ja auch ohne createn funktioniert.
Stimmt, da hast du recht. Hässlich ;-)
allesquarks hat geschrieben: Ich weiß selber auch, dass das sehr lang ist, hab ich auch nur gemacht, damit ihr das reproduzieren könnt, denke nämlich nicht, dass es so eine einfache Lösung gibt.
Naja, aber was sollten wir denn mit dem ganzen Code?
Debuggen heisst für mich immer erst das Problem "einkochen", d.h. auf's wesentliche reduzieren.
Das musst du machen, nicht wir.
Funktioniert denn FindAllFiles für sich genommen?

allesquarks
Beiträge: 4
Registriert: Mi 11. Nov 2009, 19:38

Re: Problem mit FindallFiles

Beitrag von allesquarks »

Naja das ist es ja gerade. Ich debugge ungefähr seit 4 Stunden. Und ich bin ratlos. Ich rufe Findallfiles('C:\test\','',true) in dem einen Projekt auf und es funktioniert und in dem anderen nicht. Das ist für mich völlig unlogisch, es sei denn es liegt an irgendwelchen Umgebungsvariablen.
Ich bin auch schon mit dem Debugger durchgegangen, was bis dahin alles berührt wird. Das ist recht wenig. Alles nur lokale Variablen, die eigentlich auf diese externe Unit keinen Einfluss haben sollten.
Ich habe versucht den Quellcode von meinem einen Project in das alte "funktioniertende" rüberzupasten -> funktioniert nicht. Ein neues Project mit dem Quellcode funktioniert auch nicht.
Ein leeres Projekt nur mit findallfiles -> funktioniert. Allerdings will ich nicht alles neuschreiben.

lrlr
Beiträge: 127
Registriert: Di 3. Nov 2009, 09:48

Re: Problem mit FindallFiles

Beitrag von lrlr »

das ist "relativ einfach"

"range check" einschalten, und schon hast du den fehler...

if valuepair<>0 then
begin
timearray[valuepair-1][1].time:=datetime;
timearray[valuepair-1][1].intensity:=intensity;
end else begin
timearray[valuepair-1][0].time:=datetime;

im ELSE ist valuepair = 0
timearray[valuepair-1]

also -1

dein TTime array beginnt aber bei 0...

allesquarks
Beiträge: 4
Registriert: Mi 11. Nov 2009, 19:38

Re: Problem mit FindallFiles

Beitrag von allesquarks »

Cool danke. Echt merkwürdig, dass er mir da dann keinen Fehler raushaut sondern Äonen später.

lrlr
Beiträge: 127
Registriert: Di 3. Nov 2009, 09:48

Re: Problem mit FindallFiles

Beitrag von lrlr »

ohne "range check" wird nix überprüft = kein fehler

du überschreibst "irgendwas" im speicher =

"irgendeinfehler, irgendwann..."

Antworten