Autor Beitrag
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 26.01.07 09:17 
Ich bin zur Zeit am experimentieren und lese in C# Verzeichnisstrukturen von Datenträgern ein, um diese dann in einem TreeView darzustellen. Das das Zeit-Verhalten furchtbar ist, würde ich gerne einen Vergleich machen mit einer Win32-Anwendung. Irgendwie habe ich nicht die Zeit (Faulheit spielt da sicher auch ein Rolle), das mal eben zu basteln. Hat vielleicht jemand Lust sowas für mich zu basteln?

Falls ja, hier die Anforderungen:
- Einlesen der kompletten Verzeichnisstruktur eines auswählbaren Datenträgers
- keine Fortschrittsanzeige
- Ausgabe in einem TreeView
- Ausgabe der Verarbeitungszeit

Die Ergebnisse des Vergleichs, werde ich selbstverständlich hier wiedergeben.

Hier der wesentliche Teil meines Sources (nicht optimiert):
ausblenden volle Höhe C#-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:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
Hier die Routine, die die Verzeichnisse holt
    private TreeNode GetSubDirectories(String Dir, TreeNode tn)
    {
      String[] sa;
      TreeNode[] tns;

      if (Dir.Length > 0)
      {
        try
        {
          sa = Directory.GetDirectories(Dir);

          if (sa.Length > 0// Es gibt Unterverzeichnisse
          {
            // Aufbereitung, damit nicht immer der ganze Pfad im Tree angezeigt wird
            for (int i = 0; i < sa.GetLength(0); i++)
            {
              sa[i] = sa[i].Remove(0, Dir.Length);
            }

            // Verzeichnisse in den TreeNode als Sub-Trees eintragen
            if (tn == null// Noch gar kein TreeNode vorhanden
            {
              tn = new TreeNode(Dir);
            }

            // Dimensionieren des TreeNode-Array
            tns = new TreeNode[sa.Length]; // Gleiche Länge wie das Verzeichnis-Array

            // Verzeichnisse übertragen
            for (int i = 0; i < sa.Length; i++)
            {
              tns[i] = new TreeNode(sa[i]);
            }

            for (int i = 0; i < tns.Length; i++)
            {
              tn.Nodes.Add(GetSubDirectories(Dir + tns[i].Text + "\\", tns[i]));
            }

            return tn;
          }
        }
        catch
        { /* Ungültiges Grundverzeichnis */
          sa = null;
        }
        return tn;
      }
      else
      {
        return null// kein gültiges Laufwerk
      }
    }

// Hier wird die Routine dann aufgerufen
    private void cbbDrives_SelectionChangeCommitted(object sender, EventArgs e)
    {
      string s = "";
      DriveInfo di;
      try
      {
        di = new DriveInfo(cbbDrives.Items[cbbDrives.SelectedIndex].ToString());
        try
        {
          s = s + "Type: " + di.DriveType.ToString() + Environment.NewLine;
        }
        catch { }
        try
        {
          s = s + "Name: " + di.VolumeLabel + Environment.NewLine;
        }
        catch { }
        try
        {
          s = s + "Format: " + di.DriveFormat + Environment.NewLine;
        }
        catch { }
        try
        {
          s = s + "Size: " + di.TotalSize.ToString();
        }
        catch { }
        tbxDriveInfo.Text = s;
      }
      catch 
      {
        di = null;
      }

      tvwDirectories.Nodes.Clear();
      if (di != null)
      {
        DateTime dt;

        dt = DateTime.Now;
        try
        {
          this.Cursor = Cursors.WaitCursor;
          dt = DateTime.Now;

          // Hier erfolgt der Aufruf
          TreeNode tn = GetSubDirectories(di.ToString(), null);
          tvwDirectories.Nodes.Add(tn); // tvwDirectories ist das TreeView, mit der Darstellung
          TimeSpan ts = DateTime.Now - dt;
          this.Cursor = Cursors.Default;
          MessageBox.Show(ts.ToString());
        }
        catch 
        {
          TimeSpan ts = DateTime.Now - dt;
          MessageBox.Show(ts.ToString());
          this.Cursor = Cursors.Default;
        }
      }
    }
  }


Es geht mir dabei nicht um meinen Source, sondern wirklich um einen Vergleich. Optimierungsvorschläge nehme ich aber gerne an, ist aber im Moment nicht mein primäres Ziel.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 26.01.07 11:45 
Ich würde das anders machen. Wozu alles auf einmal einlesen? :gruebel:
Das dauert doch nur unnötig lange. Auf die Idee wäre ich gar nicht gekommen, jedenfalls nicht an den Stellen, wo ich sowas bisher brauchte. Denn da mussten die ganzen Äste nicht gleich beim Start alle aufgeklappt werden.
Wenn das bei dir der Fall ist, dann geht es natürlich nicht anders.

Wie wärs jedenfalls so (ein Edit edtRootDirectory, ein Button btnSetRootDir und die TreeView trvDirectoryTree):
ausblenden volle Höhe Delphi-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:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
procedure TForm55.btnSetRootDirClick(Sender: TObject);
begin
  trvDirectoryTree.Items.Clear;
  trvDirectoryTree.Items.AddChild(trvDirectoryTree.Items.Add(
    trvDirectoryTree.Items.GetFirstNode, edtRootDirectory.Text), 'Dummy');
end;

procedure TForm55.trvDirectoryTreeExpanding(Sender: TObject; Node: TTreeNode;
  var AllowExpansion: Boolean);
  function GetAllDirs(Verzeichnis: Stringvar Ergebnisliste: TStringList{;
    IncludeSubDirs: Boolean}
): Boolean;
  var
    Search: TSearchRec;
    //Suchinformationen der aktuellen Suche
  begin
    Result := False;
    //Zunächst False als Rückgabewert, damit dann nur auf True geändert
    //werden muss, wenn etwas gefunden wird
    Verzeichnis := IncludeTrailingPathDelimiter(Verzeichnis);
    if FindFirst(Verzeichnis + '*.*',fadirectory, Search)= 0 then begin
    //Wenn überhaupt ein Verzeichnis gefunden werden kann
      repeat
        if((search.attr and fadirectory) = fadirectory)
          and(search.name[1] <> '.'then begin
        //Wenn ein (Unter-) Verzeichnis vorliegt, in diesem nachschauen
          Ergebnisliste.Add(Verzeichnis + Search.Name);
//          if IncludeSubDirs then
//            GetAllDirs(Verzeichnis + Search.Name, Ergebnisliste, True);
          Result := True;
          //Wenn Dateien im rekursiven Aufruf gefunden wurden,
          //Rückgabewert auf True setzen
        end;
        Application.ProcessMessages;
        //Rechenzeit freigeben
      until FindNext(Search) <> 0;
      //Bis ein Fehlercode zurückgegeben wird, also keine passende
      //Verzeichnis mehr vohanden ist
    end;
    SysUtils.FindClose(search);
  end;

var
  i: Integer;
  Liste: TStringList;
begin
  Liste := TStringList.Create;
  GetAllDirs(Node.Text, Liste);
  trvDirectoryTree.Items.Delete(Node.getFirstChild);
  for i := 0 to Liste.Count - 1 do
    trvDirectoryTree.Items.AddChild(trvDirectoryTree.Items.AddChild(Node, Liste[i]), 'Dummy');
  Liste.Free;
end;

Klar, es muss noch statt des ganzen Pfades in jedem Node nur der letzte Teil hinein und eine Funktion, die die ganze Kette via Parent durchgeht und den Pfad liefert her...
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 26.01.07 11:58 
user profile iconjaenicke hat folgendes geschrieben:
Ich würde das anders machen. Wozu alles auf einmal einlesen? :gruebel:
Das dauert doch nur unnötig lange. Auf die Idee wäre ich gar nicht gekommen, jedenfalls nicht an den Stellen, wo ich sowas bisher brauchte. Denn da mussten die ganzen Äste nicht gleich beim Start alle aufgeklappt werden.
Wenn das bei dir der Fall ist, dann geht es natürlich nicht anders.

Theoretisch hast Du Recht. Das Ziel ist bei mir allerdings, dass ich Informationen zu jedem Verzeichnis speichern will. Dafür muss ich leider alle Verzeichnisse haben. Insbesondere, wenn ich einen Abgleich machen muss, wenn neue Verzeichnisse hinzu kommen oder alte gelöscht werden. Zur Zeit befindet sich das aber noch in der Experimentierphase und da würde mir ein Vergleich mit Win32 natürlich helfen, mich zu entscheiden, ob es ein Win32- oder ein .NET-Projekt wird. Natürlich kann ich mir auch nochmal über das Konzept gedanken machen. Wenn es in Win32 keinen spürbaren Geschwindigkeitsvorteil gibt, dann werde ich das sowieso machen müssen. Aber soweit ist es noch nicht.

Danke für Deine Routine. Ich werde Sie noch auf meine Bedürfnisse anpassen (z.B. kein Application.ProcessMessages) und dann am Wochenende mit meiner Vergleichen.
ZeitGeist87
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1593
Erhaltene Danke: 20

Win95-Win10
Delphi 10 Seattle, Rad Studio 2007, Delphi 7 Prof., C++, WSH, Turbo Pascal, PHP, Delphi X2
BeitragVerfasst: Fr 26.01.07 12:04 
Dann war/ist meins wohl überflüssig :)

LG
Stefan
Einloggen, um Attachments anzusehen!
_________________
Wer Provokationen, Ironie, Sarkasmus oder Zynismus herauslesen kann soll sie ignorieren um den Inhalt meiner Beiträge ungetrübt erfassen zu können.
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Fr 26.01.07 12:08 
Nö, wieso?
Ich werde einfach alle testen, die ich bekomme. Mal sehen, welches die beste Variante ist. Ich nehme auch .NET-Varianten (muss nicht c# sein).
Ich werde einfach meinen Rechner als Referenz-System nehmen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 26.01.07 16:26 
user profile iconjasocul hat folgendes geschrieben:
Theoretisch hast Du Recht. Das Ziel ist bei mir allerdings, dass ich Informationen zu jedem Verzeichnis speichern will.

Alles klar, sowas hab ich mir fast schon gedacht... Ich hab das bei meiner Festplattenspeicheranalyse auch mal gebraucht, wie mir gerade einfällt, ich werd da einfach mal die Größenanalyse rausnehmen (auskommentieren meine ich, vielleicht kannst du ja auch damit was anfangen) und das posten.
Das müsste ich in C++ auch noch haben (also C++ Builder meine ich), muss ich mal suchen...

Naja, nachher, erstmal werd ich den Braten in den Ofen schieben, meine Eltern und meine Schwester scharren schon mit den Hufen... ;-)
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Fr 26.01.07 22:09 
Hallo!

Wenn Du Informationen zu jedem Verzeichnis speichern willst, ist es vielleicht ratsam, die Darstellung und die Daten ein wenig zu trennen. Ich habe das so gemacht:
ausblenden volle Höhe C#-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:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
        private void Form1_Load(object sender, EventArgs e)
        {
              
            DateTime dt;

            dt = DateTime.Now;
            try
            {
              this.Cursor = Cursors.WaitCursor;
              dt = DateTime.Now;

              // Hier erfolgt der Aufruf
              DirNode tn = null;
              GetSubNodes("E:\\"out tn);
              tvwDirectories.Nodes.Add(tn.ToTreeNode()); // tvwDirectories ist das TreeView, mit der Darstellung
              TimeSpan ts = DateTime.Now - dt;
              this.Cursor = Cursors.Default;
              MessageBox.Show(ts.ToString());
            }
            catch 
            {
              TimeSpan ts = DateTime.Now - dt;
              MessageBox.Show(ts.ToString());
              this.Cursor = Cursors.Default;
            }
        }


        public class DirNode
        {
            private string name;
            private string path;

            public string Path
            {
                get { return path; }
            }

            public string Name
            {
                get { return name; }
                set { name = value; }
            }

            private List<DirNode> subNodes;
            public List<DirNode> SubNodes
            {
                get { return subNodes; }
            }

            public DirNode(string Path)
            {
                subNodes = new List<DirNode>();
                this.Name = Path.Substring(Path.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
                this.path = Path;
            }

            public TreeNode ToTreeNode()
            {
                TreeNode result = new TreeNode(name);
                result.Tag = this;

                foreach (DirNode d in subNodes)
                    result.Nodes.Add(d.ToTreeNode());

                return result;
            }
        }

        private void GetSubNodes(string Dir, out DirNode tn)
        {
            tn = new DirNode(Dir);

            try
            {
                String[] subDirs = Directory.GetDirectories(Dir);
                foreach (string d in subDirs)
                {
                    DirNode sub = null;
                    GetSubNodes(d, out sub);
                    if (sub != null)
                        tn.SubNodes.Add(sub);
                }
            }
            catch
            { }
        }


Ich habe eine Klasse "DirNode" eingeführt, in der Du beliebige Informationen zu einem Verzeichnis ablegen kannst. Es wird zuerst einmal ein Baum dieser Klassen angelegt und kein Baum von TreeNodes. Die Klasse hat aber nun eine Methode, welche TreeNodes erstellt, die ihr entsprechen. Dabei wird die Tag-Eigenschaft jedes TreeNodes so gesetzt, dass Du bequem wieder auf die Daten zugreifen kannst.

Das Ganze war bei mir nicht schneller, aber auch nicht langsamer als Deine Methode, bietet aber IMHO mehr Möglichkeiten und eine bessere Trennung von GUI und Daten.

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".


Zuletzt bearbeitet von Christian S. am Sa 27.01.07 00:45, insgesamt 1-mal bearbeitet
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 27.01.07 00:01 
So, hier erstmal die Delphi für Win32 Version. Auch hier gibt es eine Klasse für Daten zum Ordner, die ich allerdings direkt an den jeweiligen Node angehängt habe. Die Daten sind also hier nicht getrennt.
In der Node-Klasse ist hier im Moment nur der volle Pfad gespeichert.
Einloggen, um Attachments anzusehen!
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6393
Erhaltene Danke: 147

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Sa 27.01.07 00:24 
Hey, Danke für Eure Tipps. Ihr arbeitet ja schon vor. :)
Soweit war ich noch gar nicht. Ich weiß wohl, was ich will, aber über das Wie hatte ich mir im Detail teilweise noch gar keine Gedanken gemacht.
Das geplante Projekt entsprang einer spontanen Idee und da es vermutlich nicht so aufwändig geplant ist, habe ich ohne großen Plan angefangen. Da es noch nicht endgültig ist, dass ich das Projekt durchführe, möchte ich im Moment noch nicht zu viel verraten.

@Christian:
Unser anderes Projekt habe ich nicht vergessen. Ich will aber erst noch wieder meine C#-Kenntnisse wieder vertiefen. Sind leider wieder etwas verkümmert. :cry: