Autor Beitrag
Sh3va
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mo 09.01.12 14:31 
Hallo zusammen,

ich bin noch neu in der Welt des Programmierens und vor allem ein Neuling in C#.
Habe (als Azubi) die Aufgabe bekommen ein Programm zu schreiben, dass die Ordnerstruktur (z.B.) eines Servers komplett durchgeht, Informationen speichert (ich wollte es mit einer XML-Datei versuchen) wie zum Beispiel den kompletten Pfad und die Ordnergröße (mit allen Daten/Ordner darunter).

Soweit habe ich es zum laufen bekommen, aber sobald die Ordnerstruktur umfassender wird, bleibt mein Programm stecken. Im Hintergrund läuft es weiter, dass sehe ich daran, dass in die XML-Datei weiterhin geschrieben wird, jedoch wird das Programm so gezeigt, als wenn es nicht mehr reagieren würde.

Habt ihr vllt. Tipps, wie ich mein Programm optimieren kann, oder andere Rangehensweisen an diese Problemstellung, womöglich mit einer anderen API oder Programmiersprache?

Anbei die Windows Form.
Oberfläche

ausblenden volle Höhe 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:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
namespace MainProgram
{
    public partial class Mainprogram : Form
    {

        
        static int id = 0;
        static string pathXML;
        static string pathSuche;
        
        


        public Mainprogram()
        {
            InitializeComponent();
            
        }

        // Durchlauf starten
        private void button1_Click(object sender, EventArgs e)
        {
            id = 0; // Zähler für die Anzahl der Ordner
            label1.Visible = true;
            label2.Visible = true;
            label2.Refresh();
            TempList.Items.Clear();
            XmlTextWriter textWriter = new XmlTextWriter(pathXML, null);
            DirectoryInfo target = new DirectoryInfo(pathSuche);
            textWriter.WriteStartDocument();
            textWriter.WriteStartElement("Datenbank");
            findeOrdner(target, textWriter);
            textWriter.WriteEndElement();
            // Ends the document.
            textWriter.WriteEndDocument();

            textWriter.Close();
        }

        

        // Rekursives durchgehen der Ordnerstruktur
        private void findeOrdner(DirectoryInfo d, XmlTextWriter textWriter)
        {

            if (id == 0)
            {
                DirectoryInfo[] dis = { d };
                foreach (DirectoryInfo di in dis)
                {
                    
                    try
                    {

                        // Gruppe öffnen
                        textWriter.WriteStartElement("Ordner ", id.ToString());
                        
                        // Speicherort einfügen
                        textWriter.WriteStartElement("Speicherort");
                        textWriter.WriteString(di.FullName);
                        textWriter.WriteEndElement();

                        // Ordnername einfügen
                        textWriter.WriteStartElement("Name");
                        textWriter.WriteString(di.ToString());
                        textWriter.WriteEndElement();

                        // Ordnergröße einfügen
                        textWriter.WriteStartElement("Größe");
                        textWriter.WriteString(DirSize(di).ToString());
                        textWriter.WriteEndElement();

                        // Änderungsdatum einfügen        
                        textWriter.WriteStartElement("Datum");
                        textWriter.WriteString(di.LastWriteTime.ToString());
                        textWriter.WriteEndElement();

                        textWriter.WriteEndElement();
                        // close writer

                        id++;

                        listboxschreiben(di.FullName.ToString());

                        

                        findeOrdner(di, textWriter);
                    }
                    catch (UnauthorizedAccessException)
                    {
                        continue;
                    }



                }
            }
            else
            {
                DirectoryInfo[] dis = d.GetDirectories();


                foreach (DirectoryInfo di in dis)
                {
                    try
                    {
                        if (string.Compare(di.ToString(), "~snapshot") != 0)
                        {
                            
                            // Gruppe öffnen
                            textWriter.WriteStartElement("Ordner ", id.ToString());

                            // Speicherort einfügen
                            textWriter.WriteStartElement("Speicherort");
                            textWriter.WriteString(di.FullName);
                            textWriter.WriteEndElement();

                            // Ordnername einfügen
                            textWriter.WriteStartElement("Name");
                            textWriter.WriteString(di.ToString());
                            textWriter.WriteEndElement();

                            // Ordnergröße einfügen
                            textWriter.WriteStartElement("Größe");
                            textWriter.WriteString(DirSize(di).ToString());
                            textWriter.WriteEndElement();

                            // Änderungsdatum einfügen        
                            textWriter.WriteStartElement("Datum");
                            textWriter.WriteString(di.LastWriteTime.ToString());
                            textWriter.WriteEndElement();

                            textWriter.WriteEndElement();
                            // close writer

                            id++;

                            listboxschreiben(di.FullName.ToString());



                            findeOrdner(di, textWriter);
                        }
                    }
                    catch (UnauthorizedAccessException)
                    {
                        continue;
                    }



                }
            }

            

        }

        // Momentanen Ordner in Listbox schreiben
        public void listboxschreiben(string a)
        {
            label1.Text = id.ToString();
            TempList.Items.Add(a);
            Thread.Sleep(1);
            TempList.Refresh();
            label1.Refresh();

            // Autoscroll der Listbox
            TempList.SelectedIndex = TempList.Items.Count - 1;
            TempList.SelectedIndex = -1;

        }

        // Ordnergröße ermitteln
        public long DirSize(DirectoryInfo d)
        {
            long Size = 0;
            // Add file sizes.
            FileInfo[] fis = d.GetFiles();
            foreach (FileInfo fi in fis)
            {
                Size += fi.Length;
            }
            // Add subdirectory sizes.
            DirectoryInfo[] dis = d.GetDirectories();
            foreach (DirectoryInfo di in dis)
            {
                try
                {
                    Size += DirSize(di);
                }
                catch (UnauthorizedAccessException)
                {
                    continue;
                }
            }
            return (Size);
        }       
      
        
        // Speicherort der XML-Datei festlegen über Textbox1
        private void button2_Click(object sender, EventArgs e)
        {
            if (textBox1.Text != "")
            {
                pathXML = textBox1.Text;
                
                button3.Visible = true;
            }            
        }

        // Startordner des Durchlaufs festlegen
        private void button3_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                this.textBox2.Text = folderBrowserDialog1.SelectedPath;
                pathSuche = folderBrowserDialog1.SelectedPath;
                btnStart.Visible = true;
            }
        }      
    }
}
Einloggen, um Attachments anzusehen!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 09.01.12 14:51 
Die ganze Ordnerfunktionalität steckt letztlich in der Windows API. Eine andere Programmiersprache zu wählen hilft also nicht da die API die gleiche bleibt. Mit der Geschwindigkeit wirst du also mehr oder weniger leben müssen.

Um die GUI sauberer zu gestalten solltest denn Vorgang des Ordners scannens in einen eigenen Thread(oder mehrere) auslagern.
Sh3va Threadstarter
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mo 09.01.12 15:03 
Hmm, okay.
Ich habe nur gehofft, dass es dennoch eine Möglichkeit zur Geschwindigkeitserhöhung gibt.
Wenn man sich anschaut, wie "schnell" die Aufzählung der Ordner,Daten und deren Größe geht, wenn man auf die Eigenschaften eines Ordners geht, dachte ich, man könnte i.wie daran kommen.

Mit Multithreading habe ich mich noch nicht wirklich beschäftigt. Hast du vllt. hilfreiche Links o.ä. wo ich mich reinlesen kann?

Danke aber für deine Antwort!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 09.01.12 15:42 
Zitat:
Ich habe nur gehofft, dass es dennoch eine Möglichkeit zur Geschwindigkeitserhöhung gibt.

Ich habe nicht gesagt das du aus deiner Lösung nicht mehr Geschwindigkeit herausholen kannst sondern nur das der begrenzende Faktor nicht die Programmiersprache sondern die Windows API ist. Und natürlich die Qualität des geschriebenen Codes ;)

Zum Beispiel das ständige Updaten der GUI im Code (GUI ist immer langsam und du rufst ständig die listboxschreiben Methode auf) wird das vermutlich deutlich verlangsamen. Möglicherweise ist DirectoryInfo auch nur eine mäßige Kapselung(insbesondere die GetFiles Methode) und man sollte sich direkt an die Windows API wenden (also FindFirstFile, FindNextFile etc.). Möglicherweise ist dein schreiben in die Xml Datei langsam, weil du ständig in die Datei flushst oder so (habe deinen Code nicht genau inspiziert).
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4798
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 09.01.12 17:58 
Hallo Sh3va :welcome:

wenn du auch selber deinen Code schlafen legst, ist das ja kein Wunder:
Sh3va hat folgendes geschrieben:

ausblenden C#-Quelltext
1:
Thread.Sleep(1);					


Bei 1000 Dateien wird also schon 1 Sekunde insgesamt gewartet.

Zum Thema "Multithreading" gibt es z.B. folgenden Artikel Multi-Threaded Programmierung
Dann gibt es unter WinForms auch noch den BackgroundWorker, in dessen DoWork-Ereignis du das Auslesen der Dateistruktur durchführen müßtest und in dem ProgressChanged-Ereignis dann das Aktualisieren der GUI stattfinden würde (aber wie von Ralf schon angesprochen, nicht zu häufig - am besten erst die Daten sammeln und dann z.B. jede Sekunde per listBox.AddRange() hinzufügen).

P.S. Außerdem sehe ich gerade noch, daß du ja mehrmals die Ordner durchgehst, in dem du vorher noch DirSize() aufrufst. Selbst wenn du die Ordnergröße zuerst in die XML-Datei schreiben mußt, und danach erst die Dateien und Unterordner, so könntest du die Daten ja cachen. (Würden die Dateien während deines Programmlaufs geändert, z.B. einige gelöscht oder neu hinzugefügt, so würde bei dir ja die Ordnergröße evtl. nicht stimmen.)
Da steckt also noch einiges an Optimierungspotential drin...
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 09.01.12 18:29 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Bei 1000 Dateien wird also schon 1 Sekunde insgesamt gewartet.
Um genau zu sein eher mehrere Sekunden, da eine Millisekunde Wartezeit nicht möglich ist.

Das andere generelle Problem:
Du aktualisierst ständig die ListBox, refreshst die, ...
Das kostet enorm Zeit.

Besser ist es, wenn du wie schon erwähnt einen Thread benutzt und nur alle meinetwegen 500 Millisekunden den aktuellen Ordner ausgibst. Und ggf. die Liste um die neuen Einträge ergänzt. Aber die Liste würde ich wenn möglich erst am Ende aktualisieren, weil das relativ viel Zeit kostet. Bei Threads sollte das aber auch besser werden, wenn du das richtig umsetzt.
Sh3va Threadstarter
Hält's aus hier
Beiträge: 6



BeitragVerfasst: Mi 11.01.12 10:43 
Danke für die Antworten und die Anregungen.
Ich werde mich damit beschäftigen, sobald ich dann wieder die Zeit habe.

Werde mich sicher nochmal hier melden, um mit euch über meine neuen Ansätze zu diskutieren :D

ceeyá, Sh3va