Avatar billede sandrasmurf Nybegynder
18. marts 2006 - 02:18 Der er 8 kommentarer og
1 løsning

Optimering af filsøgning

Hej Eksperter

Jeg har en flaskehals i mit system og ville høre om i kunne hjælpe med en smule optimering. Jeg har siddet og hygget mig lidt med problemet, men trænger nu til noget prof hjælp til at komme videre(Se timestamp på spørgsmål Hehe)

Problemet er basically filsøgning:
Ud fra en mappestruktur med subdirs i en ukendt dybde og givet et filnavn ønskes det at finde den komplette sti til filen med dette filnavn. Input er altså et startDir(Eks. c:\) og et filnavn(eks minfil.ext), der muligvis er placeret i mappestrukturen
under startDir. Bemærk at der kan være sub-subdirs i en ukendt dybde.

Jeg har bikset noget rekursiv kode sammen, der breaker, når en match er fundet. Se nedenstående klasse.

----------------------------
using System.IO;

public class DirSearcher
{
  private string startDir;
  private string searchString;
  private bool itemFound;
  private string resultPath;
 
  public DirSearcher(string startDir)
  {
      this.itemFound = false;           
      this.searchString = null;
      this.startDir = startDir;
      this.resultPath = null;
  }

  // Start the search for fileName in startDir using
  // recursive method searchDir
  public string search(string fileName)
  {
      this.searchString = fileName;
      this.resultPath = "No match";
      searchDir(startDir);
      return result;
  }

  private void searchDir(string dir)
  {
      if (!itemFound)  // Dont investigate further, a match has been found
      {
        try
        {
            foreach (string d in Directory.GetDirectories(dir))
            {
              foreach (string f in Directory.GetFiles(d, searchString))
              {
                  itemFound = true;
                  return f;
              }
              searchDir(d);
            }
        }
        catch (Exception e) {}
      }
  }

  static void Main()
  {
      DirSearcher ds = new DirSearcher("C:\\");
      string res = ds.search("dotnetfx.exe");
      Console.WriteLine(res);
      Console.Read();   
  }
}

Jeg har dog behov for at kalde search metoden 100-500 gange på en mappestruktur i ukendt dybde, der let kan indeholde 70000+
filer. Dette er i øjeblikket laaaaaangsomt. Så spørgsmålet til jer er.... Kan metoden optimeres?

Jeg har kigget lidt på brug af Indexing Service i windows, men kan ikke finde et eksempel der uddyber emnet. Er det måske
vejen frem.

Det skal nævnes, at jeg allerede har et funktionelt alternativ, hvor der først genereres en xml fil med de ønskede metadata
fra alle filer i mappestrukturen(nej jeg ville ikke bare søge efter filer), hvorefter filnavnet kan benyttes som nøgle til at
tilgå den ønskede fils metadata. Dette kræver dog, at der på forhånd genereres en temmelig stor xml fil og dette tager også lang tid. Jeg/vi vil derfor gerne undersøge om xml genereringen kan spares væk ved at søge efter filerne direkte.

Ser frem til at høre jeres bud på optimeringer eller alternative fremgangsmåder.

Allan

\* A programmer is just a tool to convert coke and smokes into code */
Avatar billede arne_v Ekspert
18. marts 2006 - 02:28 #1
den hurtigste løsning må være en enkelt scan som læser alle 70000+ filer ind
i en Hashtable med simpelt filnavn som key og fuldt filnavn eller dir som value

så kan du lave opslag på et par milliontedele sekunder

det koster så lidt memory (i størrelsesordenen 25-50 MB)
Avatar billede sandrasmurf Nybegynder
18. marts 2006 - 02:28 #2
Jeg prøver lige at poste koden igen.

Der er et par bugs i den kode jeg fik sat ind. Glemte at jeg af pædagogiske årsager ændrede result-variablen til at hedde resultPath. Det slog ikke igennem i hele koden.

Please forgive klokken er halv 3 om natten og det er ikke nemt at se koden i de små vinduer man skal skrive spørgsmålet i :-)

using System.IO;

public class DirSearcher
{
  private string startDir;
  private string searchString;
  private bool itemFound;
  private string resultPath;
 
  public DirSearcher(string startDir)
  {
      this.itemFound = false;           
      this.searchString = null;
      this.startDir = startDir;
      this.resultPath = null;
  }

  // Start the search for fileName in startDir using
  // recursive method searchDir
  public string search(string fileName)
  {
      this.searchString = fileName;
      this.resultPath = "No match";
      searchDir(startDir);
      return resultPath;
  }

  private void searchDir(string dir)
  {
      if (!itemFound)  // Dont investigate further, a match has been found
      {
        try
        {
            foreach (string d in Directory.GetDirectories(dir))
            {
              foreach (string f in Directory.GetFiles(d, searchString))
              {
                  itemFound = true;
                  resultPath = f;
              }
              searchDir(d);
            }
        }
        catch (Exception e) {}
      }
  }

  static void Main()
  {
      DirSearcher ds = new DirSearcher("C:\\");
      string res = ds.search("dotnetfx.exe");
      Console.WriteLine(res);
      Console.Read();   
  }
}
Avatar billede arne_v Ekspert
18. marts 2006 - 02:31 #3
den eneste optimering jeg lige kan se vil være altid at returnere lige så snart
du har fundet filen

det bør spare ca. 50%
Avatar billede sandrasmurf Nybegynder
18. marts 2006 - 02:35 #4
Arne. Point taken!!!

Det vil kræve en køretid i samme størrelsesorden som den nuværende kode kræver for den første søgning, men derefter vil de næste 499 søgninger være tæt på gratis..

Er der nogle kommentarer til den rekursive søgningteknik. Kan det gøres hurtigere eller har jeg fundet vejen frem.
Avatar billede arne_v Ekspert
18. marts 2006 - 02:40 #5
netop

----

kun den tidlige retur som beskrevet ovenfor
Avatar billede sandrasmurf Nybegynder
18. marts 2006 - 02:40 #6
hehe.. Må man nu ikke engang stille spørgsmålet før du svarer.....

Jeg har haft lidt problemer med at bryde ud af det rekursive kald. Derfor er der indsat variablen itemFound i class scope. Hvis jeg returnerer en værdi fra searchDir, så vil den jo overskrive min resulatet string var i search(), når det rekursive kald fortsætter???

Min ingeniør uddannelse rækker ikke til at stoppe rekursiviteten uden at bruge itemFound variablen. Kan jeg breake på andre måder.
Avatar billede arne_v Ekspert
18. marts 2006 - 02:50 #7
måske

  private void searchDir(string dir)
  {
        try
        {
            foreach (string d in Directory.GetDirectories(dir))
            {
              foreach (string f in Directory.GetFiles(d, searchString))
              {
                  itemFound = true;
                  resultPath = f;
                  return;
              }
              searchDir(d);
              if(itemFound) return;
            }
        }
        catch (Exception e) {}
  }
Avatar billede sandrasmurf Nybegynder
18. marts 2006 - 03:00 #8
Det ser umiddelbart fornuftigt ud. Men hvorfor skulle det dog også være andet.

Jeg leger lidt med koden i morgen og lukker så spørgsmålet. Du kan jo ligge et svar på forhånd.

Takker for hjælpen.
Avatar billede arne_v Ekspert
18. marts 2006 - 03:05 #9
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester