AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller Suche
Thema durchsuchen
Ansicht
Themen-Optionen

Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller Suche

Ein Thema von juergen · begonnen am 4. Jul 2015 · letzter Beitrag vom 12. Jul 2015
Antwort Antwort
Seite 3 von 4     123 4      
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.537 Beiträge
 
Delphi 11 Alexandria
 
#21

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 00:20
Wenn ich das richtig verstehe, geht es dir nicht um eine schnelle gezielte Dateisuche, sondern um einen rasch reagierenden Dateifilter, der aber meistens die komplette Tabelle durchsuchen muss, weil der gesuchte Namensteil nicht unbedingt am Anfang des Dateinamens steht.

In so einem Fall ist eine in-Memory Lösung wie zum Beispiel eine Stringliste sicher schneller als jede Datenbank.
Also ich habe keine Ahnung, wie lange eine typische Datenbank braucht, um ein Ergebnis zurück zu liefern. Ich haben in meinen Dateimanager-Programm bei der Suchen-Option statt tatsächlich in den "echten" Ordnern zu suchen, eine Alternative, in der Datenbank zu suchen. Die Dateien muss man zuvor einmal eingelesen haben (gerade mal getestet, auf einer SSD wird Laufwerk C:\mit 800.000 Dateien in ca. 1 Minute eingelesen).

Die Suche nach einer Datei (bzw. Filter) dauert dann ca. 2 Sekunden. Die Daten in der Datei werden in eine einfache Stringlist geladen, sind nicht sortiert, es müssen alle Einträge durchlaufen werden. Wenn man hier mit Multithreading arbeiten würde, könnte man die Suche zeitlich noch deutlich optimieren. Bei den 800.000 Dateien wird die Datendatei ca. 46 MB groß, eingelesen in der Arbeitsspeicher werden ca. 100 BM benötigt. In der Datei wird das Verzeichnis (aber nicht mehrfach) und der Dateiname, das Datum, die Größe und das Änderungsdatum erfasst.

Das Suchergebnis kann ich noch mal durch einen 2. Filter eingrenzen (siehe anliegenden Screenshot)
Miniaturansicht angehängter Grafiken
suchen.jpg  
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#22

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 00:30
Zitat:
Was du jetzt vor hast klingt für mich, was Microsoft mal geplant hatte, das Dateisystem in eine DB zu überführen.
Wie kommst Du darauf, er legt ja nur die Pfade ab, nicht den Inhalt.
Und die ganzen Infos: MP3 Tag, EXIF-Daten, Datum usw.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#23

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 01:16
Mmh, reicht da auch ein externes Tool wie Everything, Hddb oder sowas, die die MFT indexieren?

MfG Dalai
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#24

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 07:53
Wenn der TE nur nach Dateinamen suchen möchte, reichen die hier vorgestellten Verfahren.

Ansonsten würde ich ein Fulltext-System wie Lucene empfehlen oder irgend etwas anderes 'Fertiges', wie mein Vorredner schon anmerkte.

Bitte macht nicht den Fehler, für ein Standardproblem etwas eigenes zu programmieren. Außer exorbitanten Kosten gewinnt man dabei gar nichts.

Siehe auch: https://de.wikipedia.org/wiki/Not-invented-here-Syndrom
  Mit Zitat antworten Zitat
Benutzerbild von mschaefer
mschaefer

Registriert seit: 4. Feb 2003
Ort: Hannover
2.032 Beiträge
 
Delphi 12 Athens
 
#25

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 09:45
Moin zusammen,

Wir hatten mal einen Thread der sich mit der Geschwindikgeit von Listen beschäftigt hat und bei ID und Pfad-Listen fällt mir gleich Hashlist und DirectoryList ein. Schaut doch mal bei Alzaimar´s -Listen-Thread. Man kann sich aus dem Beispielprogramm eine Liste heraussuchen.

Grüße in die Runde
Martin Schaefer
Phaeno
  Mit Zitat antworten Zitat
jobo

Registriert seit: 29. Nov 2010
3.072 Beiträge
 
Delphi 2010 Enterprise
 
#26

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 12:34
Was wichtig ist:
Performante Datei-Suche. Es gilt oft ca. 500.000 Datensätze nach Dateinamen zu durchsuchen und zu filtern. Das Ganze muss unter 1 s ablaufen.
Also ich hab hier ein Lazarusprogramm, das unter der Sekunde bleibt bei ca 550000 Datenätzen. Das ist aber nicht optimiert auf sowas.
Gruß, Jo
  Mit Zitat antworten Zitat
Benutzerbild von juergen
juergen

Registriert seit: 10. Jan 2005
Ort: Bönen
1.174 Beiträge
 
Delphi 11 Alexandria
 
#27

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 12:40
Hallo zusammen,

ich habe nun eine -naja- Q&D-Lösung, die für mich reicht. Externe Tools bieten meines Wissens nur das durchsuchen der MFT bei lokalen Laufwerken an. Aber vor allem möchte ich mein Tool nach meinen Bedürfnissen.
Ich bleibe nun bei meinen 2 Stringlisten.
In der ersten TStringList werden Dateipfad+Name (und jetzt neu) das Datum gespeichert (getrennt durch 5 Doppelpunkte). Anzeigen tue ich in einer TListbox im virtullen Modus nur die Dateinamen. In einer für Textsuche angepassten weiteren StringList von alzheimer speichere ich nur die Dateinamen und im Objekt die eindeutige Nummer der "Hauptliste". Somit habe ich in meiner Suchvorschau immer den benötigten, direkten Verweis auf die Hauptliste:
Delphi-Quellcode:
ExtractFileName(copy(sl_Master[Integer(SearchForm.Listbox1.Items.Objects[i])], 1,
  pos(':::::', sl_Master[Integer(SearchForm.Listbox1.Items.Objects[i])])-1)
Die Suche bleibt immer noch so schnell, dass ich meine "Live"-Suche anwenden kann (bei jeder neuen Eingabe eines neuen Buchstaben wird neu gesucht).
MP3-und Exif-Tags lese ich erst aus, wenn die Datei in der Listbox angeklickt wird.
Da ich die Hauptliste sortiere nach Name, Verzeichnis, Dateiendung und nach Datum, benötige ich diese Infos ja in der Hauptliste. Hinzukommen wird noch die Sortierung nach Bewertung (MP3). Aber das funktioniert ja nach dem jetzigen System, indem ich einfach 6 Doppelpunkte als weiteren Trenner für die Bewertungen verwende.

Das Ganze ist für mich überschaubar, umsetzbar und nun auch erweiterbar. Ist sicherlich nicht elegant (da ich mit copy() mir immer die "Teile" aus der Hauptstringlist heraus fischen muss) und eine 2. Liste verwalten muss, aber erfüllt erstmal seinen Zweck.

Danke für eure Ideen und Ratschläge!
Jürgen
Indes sie forschten, röntgten, filmten, funkten, entstand von selbst die köstlichste Erfindung: der Umweg als die kürzeste Verbindung zwischen zwei Punkten. (Erich Kästner)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#28

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 14:51
Wenn du eine ListView nimmst mit OwnerData := True , dann kannst du das mit einer TObjectList<T> sehr einfach behandeln.
Delphi-Quellcode:
type
  TDataItem = class
    property Name : string;
    property Date : TDateTime;
  end;

  TMyForm = class( TForm )
    ListView1 : TListView;
    procedure ListView1Data( Sender:TObject; Item : TListViewItem );
  private
    FAllList : TObjectList<TDataItem>;
    FHitList : TList<TDataItem>;
    procedure SetHitList( AHitList : TList<TDataItem> );
  end;

procedure TMyForm.SetDataList( AHitList : TList<TDataItem> );
begin
  // Alte Liste löschen
  if FHitList <> FAllList then
    FreeAndNil( FHitList );

  // Neue Liste setzen
  FHitList := AHitList;
  // Items.Count setzen
  if Assigned( FHitList ) then
    ListView1.Items.Count := FHitList.Count
  else
    ListView1.Items.Count := 0;
end;

procedure ListView1Data( Sender:TObject; Item : TListViewItem );
var
  LItem : TDataItem;
begin
  LItem := FHitList[Item.Index];
  Item.Caption := LItem.Name;
  Item.SubItems.Add( DateToStr( LItem.Date ) );
end;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.445 Beiträge
 
Delphi 11 Alexandria
 
#29

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 15:26
Ich bleibe nun bei meinen 2 Stringlisten.
„Wer als Werkzeug nur einen Hammer hat, sieht in jedem Problem einen Nagel.“
Wer als Werkzeug nur eine TStringlist kennt, für den sind alles Strings
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#30

AW: Konzeptfrage: Datenhaltung vieler Datei-Infos und deren Darstellg mit schneller S

  Alt 6. Jul 2015, 16:51
Hier mal so ein Minimal-Projekt im Anhang (Source + EXE) - ohne Threading, alles in einem Thread (der Start könnte etwas länger dauern)
Delphi-Quellcode:
unit Model_FileInfo;

interface

uses
  System.Generics.Collections,
  System.SysUtils;

type
  TObjectActionResult<TResult: class> = reference to procedure( AResult: TResult; AException: Exception; var ADispose: Boolean );

  TFileInfo = class
  private
    FFullName: string;
    function GetFileName: string;
    function GetPath: string;
  public
    constructor Create( const AFileName: string );
    property FullName: string read FFullName;
    property FileName: string read GetFileName;
    property Path: string read GetPath;
  end;

  TFileInfoList = class( TObjectList<TFileInfo> )
    procedure Query( APredicate: TPredicate<TFileInfo>; callback: TObjectActionResult<TFileInfoList> );
  end;

implementation

uses
  System.IOUtils;

{ TFileInfoList }

procedure TFileInfoList.Query( APredicate: TPredicate<TFileInfo>; callback: TObjectActionResult<TFileInfoList> );
var
  LItem: TFileInfo;
  LResult: TFileInfoList;
  LDispose, LDummy: Boolean;
begin
  LDispose := True;
  LResult := nil;
  try
    try

      LResult := TFileInfoList.Create( False );
      for LItem in Self do
      begin
        if APredicate( LItem ) then
          LResult.Add( LItem );
      end;

    except
      on E: Exception do
      begin
        callback( nil, E, LDummy );
        Exit;
      end;
    end;
    callback( LResult, nil, LDispose );

  finally
    if LDispose then
      LResult.Free;
  end;
end;

{ TFileInfo }

constructor TFileInfo.Create( const AFileName: string );
begin
  inherited Create;
  FFullName := AFileName;
end;

function TFileInfo.GetFileName: string;
begin
  Result := TPath.GetFileName( FFullName );
end;

function TFileInfo.GetPath: string;
begin
  Result := TPath.GetFullPath( FFullName );
end;

end.
Delphi-Quellcode:
unit Form_Main;

interface

uses
  Model_FileInfo,
  System.Diagnostics,
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class( TForm )
    ListView1: TListView;
    Edit1: TEdit;
    StatusBar1: TStatusBar;
    QueryTimer: TTimer;
    procedure ListView1Data( Sender: TObject; Item: TListItem );
    procedure Edit1Change( Sender: TObject );
    procedure QueryTimerTimer( Sender: TObject );
  private
    FQueryWatch: TStopwatch;

    FAllList: TFileInfoList;
    FHitList: TFileInfoList;
    procedure SetHitList( AHitList: TFileInfoList );
    procedure BuildAllList( );
    procedure QueryCallback( AResult: TFileInfoList; AException: Exception; var ADispose: Boolean );
    procedure QueryData( const QueryStr: string );
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  System.IOUtils;

{ TForm1 }

procedure TForm1.AfterConstruction;
begin
  inherited;
  BuildAllList;
  QueryData( Edit1.Text );
end;

procedure TForm1.BeforeDestruction;
begin
  inherited;
  SetHitList( nil );
  FreeAndNil( FAllList );
end;

procedure TForm1.BuildAllList;
var
  LPath, LFileName: string;
begin
  FAllList := TFileInfoList.Create( True );

  for LPath in TArray<string>.Create(
    {} TPath.GetPublicPath,
    {} TPath.GetLibraryPath,
    {} TPath.GetDocumentsPath,
    {} TPath.GetDownloadsPath,
    {} TPath.GetPicturesPath,
    {} TPath.GetMusicPath,
    {} TPath.GetMoviesPath ) do
  begin
    for LFileName in TDirectory.GetFiles( LPath, '*.*', TSearchOption.soAllDirectories ) do
    begin
      FAllList.Add( TFileInfo.Create( LFileName ) );
    end;
  end;

end;

procedure TForm1.Edit1Change( Sender: TObject );
begin
  QueryTimer.Enabled := True;
end;

procedure TForm1.ListView1Data( Sender: TObject; Item: TListItem );
var
  LItem: TFileInfo;
begin
  LItem := FHitList[ Item.Index ];
  Item.Caption := LItem.FileName;
  Item.SubItems.Add( LItem.Path );
end;

procedure TForm1.QueryCallback( AResult: TFileInfoList; AException: Exception; var ADispose: Boolean );
begin
  SetHitList( AResult );
  ADispose := False;

  FQueryWatch.Stop;

  if Assigned( AException ) then
    StatusBar1.Panels[ 1 ].Text := AException.ToString( )
  else
    StatusBar1.Panels[ 1 ].Text := string.Format( 'query finished in (%d ms)', [ FQueryWatch.ElapsedMilliseconds ] );

end;

procedure TForm1.QueryData( const QueryStr: string );
var
  LQueryStrArr: TArray<string>;
begin
  StatusBar1.Panels[ 1 ].Text := 'query data...';

  FQueryWatch := TStopwatch.StartNew;

  if QueryStr.Trim( ) = 'then
    FAllList.Query(
      function( AFileInfo: TFileInfo ): Boolean
      begin
        Result := True;
      end, QueryCallback )
  else
  begin
    LQueryStrArr := QueryStr.ToLower( ).Split( [ ' ' ] );
    FAllList.Query(
      function( AFileInfo: TFileInfo ): Boolean
      var
        LQueryStr: string;
      begin
        for LQueryStr in LQueryStrArr do
        begin
          if not AFileInfo.FullName.ToLower.Contains( LQueryStr ) then
            Exit( False );
        end;
        Result := True;
      end, QueryCallback );
  end;
end;

procedure TForm1.QueryTimerTimer( Sender: TObject );
begin
  TTimer( Sender ).Enabled := False;
  QueryData( Edit1.Text );
end;

procedure TForm1.SetHitList( AHitList: TFileInfoList );
begin
  if ( FHitList <> FAllList ) and ( FHitList <> AHitList ) then
    FreeAndNil( FHitList );
  FHitList := AHitList;

  if Assigned( FHitList ) then
  begin
    ListView1.Items.Count := FHitList.Count;
    ListView1.Repaint;
  end
  else
  begin
    ListView1.Items.Count := 0;
  end;

  ListView1.Visible := Assigned( FHitList );

  StatusBar1.Panels[ 0 ].Text := ListView1.Items.Count.ToString( );
end;

end.
Angehängte Dateien
Dateityp: zip dp_185758_minimal.zip (902,6 KB, 15x aufgerufen)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 4     123 4      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz