AnDi_P Geschrieben 26. Februar 2010 Teilen Geschrieben 26. Februar 2010 Hallo zusammen, ich habe eine kleines Problem bei einer Windows Forms Anwendung. Ich lasse dort bei einem MouseDoubleClick-Event den Inhalt einer Netzwerkfreigabe in einem DataGridView anzeigen. Wenn ich nur den Inhalt aufliste, dauert es bei ca. 4000 Dateien ~1 sec. Nun möchte ich aber zusätzlich, in einer extra Spalte, auch noch die Dateigröße mit anzeigen lassen. Bisher habe ich es so, dass bei jedem Zufügen einer Zeile zu dem DataGridView (for-Schleife), ein FileInfo-Objekt erzeugt wird, und mit der Eigenschaft "length" die Größe ausgelesen wird. Mit dieser Methode dauert das Anzeigen des selben Verzeichnisses allerdings ~15-18 sec., was ich als zu lang empfinde Ich denke mal, dass das damit zusammenhängt, das für jede Datei im Verzeichnis, ein extra Speicherbereich angelegt wird, oder..? Gibt es eine andere performantere Möglichkeit, die Dateigröße auszulesen? Bei Windows geht dies ja auch wesentlich schneller. Habe bisher bei google leider nichts brauchbares gefunden. Da durch die Beschreibung denke ich mal das grundlegende Problem schon beschrieben ist, poste ich erstmal nicht den Quelltext. Vielen Dank im Vorraus. MfG AnDi_P Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Pointerman Geschrieben 26. Februar 2010 Teilen Geschrieben 26. Februar 2010 Moin! Hast Du es mal mit DirectoryInfo.GetFileSystemInfos versucht? Die Methode liefert Dir gleich ein Array mit den FileInfos aller Dateien im Verzeichnis zurück. Eventuell beschleunigt das die Sache etwas. Mehr zum Thema: DirectoryInfo.GetFileSystemInfos-Methode (System.IO) Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
lbm1305 Geschrieben 26. Februar 2010 Teilen Geschrieben 26. Februar 2010 Eventuell in einem anderen Thread laufen lassen Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
MidnightRun Geschrieben 27. Februar 2010 Teilen Geschrieben 27. Februar 2010 Eventuell in einem anderen Thread laufen lassen Ich würde wenn es nicht schneller geht auf P/Invoke auch nocht setzten. WinAPI. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
AnDi_P Geschrieben 27. Februar 2010 Autor Teilen Geschrieben 27. Februar 2010 Hallo, erstmal Danke für Eure Antworten. Das Auslesen der Ordner-Inhalte habe ich bereits in einem eigenen Thread laufen. Die DirectoryInfo.GetFileSystemInfos-Methode werde ich mir mal anschauen, kann ich aber leider erst Montag wieder bei der Arbeit testen, in wie weit das Verbesserung bringt. Mit dem P/Invoke kenne ich mich leider noch nicht aus, bin noch Programmier-Anfänger. Werde mir bei Bedarf sonst mal was dazu "ergooglen" Melde mich dann nochmal. MfG AnDi_P Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
AnDi_P Geschrieben 1. März 2010 Autor Teilen Geschrieben 1. März 2010 Guten Morgen, so, ich habe mir mal die DirectoryInfo.GetFileSystemInfos-Methode angeschaut, aber leider keine Möglichkeit gefunden, dadrauf direkt per FileInfo zuzugreifen. Ich vermute mal eher, dass Du die DirectoryInfo.GetFiles-Methode meintest? Mit dieser errreiche ich allerdings auch keine Performance-Verbesserung. Hier mal ein kleiner Code-Ausschnitt: DirectoryInfo dirInfo = new DirectoryInfo(listPath.Text); FileInfo[] dirFiles = dirInfo.GetFiles(); lblNumberOfFiles.Text = dirFiles.Length.ToString(); for (int i = 0; i < dirFiles.Length; i++) { dataGridFiles.Rows.Add(dirFiles[i].Name, dirFiles[i].Length); } Mache ich da vielleicht einen generellen Denk-Fehler, oder sieht das soweit in Ordnung aus? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Mcolli Geschrieben 7. März 2010 Teilen Geschrieben 7. März 2010 (bearbeitet) Hallo, ich habe versucht Dein Problem zuhause mit dem Sample Code nachzubilden, konnte aber den Performanceverlust nicht spüren. Ich habe allerdings kein Netzwerkfestplatten zu hause und in sofern musste ich das ganze mit nem lokalen Ordner versuchen (mit "nur" 2k Dateien drin). Nicht desto trotz wäre ich nicht Olli wenn ich Dir nicht zu mindestens einen Lösungsvorschlag unterbreiten würde und ich hab sogar zwei. Der erste is sehr einfach aber evtl nicht ausreichend für deine Zwecke: Binde das Array an deine DataGridView: DirectoryInfo dirInfo = new DirectoryInfo(listPath.Text); FileInfo[] dirFiles = dirInfo.GetFiles(); lblNumberOfFiles.Text = dirFiles.Length.ToString(); dataGridFiles.DataSource = dirFiles; Der Zweite vorschlag ist komplezierter aber dafür auch sehr schön: Du trennst das Iterieren über die Dateien und das Erzeugen einer neuen "Row". Das Dauert zwar noch ein wenig länger dafür sind die ersten 40+ "Row"s annähernd sofort da und der Benutzer kriegt nur bedingt mit das neue "Row"s reingeschoben werden. Ausserdem bleibt so Deine Anwendung interaktiv: Vorweg: Kopier die folgenden Codes erstmal in deine Form rein und lies dann was passiert .... so wirkt das nicht ganz so verwirrend (gerade wenn Dir "Delegates" und "Events" und "Invoke"-Methode nichts sagen). Also wie wird gemacht: Zu erst deklarierst du ein "Delegate" und ein "Event" innerhalb deiner Form: public partial class Form1 : Form { [INDENT] public delegate void AddRowDelegate(DataGridViewRow theRow); public event AddRowDelegate RequestRowAdding; ........ [/INDENT] } Anschliesend meldest Du im Konstruktor deiner Form einen Handler für Dein Event an. Das machst du indem Du diese Zeile beim Kosntruktor hinzufügst: this.RequestRowAdding += new AddRowDelegate(OnRequestRowAdding);[/INDENT] "OnRequestRowAdding" ist eine Methode die jetzt hinzugefügt werden muss. Diese muss mit der Signatur des Delegates "AddRowDelegate" übereinstimmen Also Rückgabetyp:void und Parameter:DataGridViewRow Gesagt getan wir fügen die Methode hinzu: private void OnRequestRowAdding(DataGridViewRow theRow) { [INDENT] this.Invoke(new AddRowDelegate(addRowHandle), new object[] { theRow });[/INDENT] } Jetzt sollte sich Dir die Frage stellen wiese die als Parameter übergebene "DataGridViewRow" nicht deiner DataGridView hinzugefügt wird sondern noch mal ein "AddRowDelegate" erzeugt wird.... Das soll verhindern, dass, wenn das oben benannte event aus einem anderen Thread heraus gecallt wird, es zu einer IllegalCrossThreadOperation kommt.... Also die " void OnRequestRowAdding(DataGridViewRow)" -Methode leitet einen neuen "AddRowDelegate" mittels der "this.Invoke(....)"- Methode an den Thread weiter in dem "this" gerade läuft .... also an den Windows.Forms-Thread. "addRowHandle" ist also der "Handler" für die Invoke-Methode. diese Methode sieht so aus: private void addRowHandle(DataGridViewRow theRow) { [INDENT]dataGridFiles.Rows.Add(theRow);[/INDENT] } Das Fetschen der Dateien wird praktisch genau so wie bei deiner Methode gemacht: deine Methode sollte dann So aussehen dg_anzeige.DataSource = null; Thread worker = new Thread(new ThreadStart(delegate() { [INDENT] DirectoryInfo dirInfo = new DirectoryInfo(@"D:\WINDOWS\system32"); FileInfo[] dirFiles = dirInfo.GetFiles(); int count = dirFiles.Length; for (int i = 0; i < dirFiles.Length; i++) { DataGridViewRow myNewRow = new DataGridViewRow(); DataGridViewTextBoxCell cell2add = new DataGridViewTextBoxCell(); cell2add.Value = dirFiles[i].Name; myNewRow.Cells.Add(cell2add); cell2add = new DataGridViewTextBoxCell(); cell2add.Value = dirFiles[i].Length; myNewRow.Cells.Add(cell2add); this.RequestRowAdding(myNewRow); } [/INDENT] })); worker.Start(); Bearbeitet 7. März 2010 von Mcolli Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Mcolli Geschrieben 7. März 2010 Teilen Geschrieben 7. März 2010 ich hab Vergessen den Kompletten Code einzufügen: Also als Anhgang fidnest du eine Sample Klasse ..... als .txt. Diese Klasse ist eine Form incl des Designer Codes ... also kansnte einfach in ".cs" umbennen, einem Projekt hinzufügen und mittels "(new Class1()).Show()" dann anzegien lassen .... der Pfad "D:\Windows\System32" wird bei dir nicht auffindbar sein.Neues Textdokument.txt Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
AnDi_P Geschrieben 11. März 2010 Autor Teilen Geschrieben 11. März 2010 Hallo, erstmal vielen Dank für Deine Hilfe. Konnte es leider erst jetzt testen Also der erste Lösungsvorschlag hat leider nicht gefruchtet, da du bei diesem nicht die einzelnen Dateigrößen ausgelesen hast, was ja bei mir der Flaschenhals war, sondern wie es für mich aussieht, die Größe aller Dateien des FileInfo-Arrays. Nur das Anzeigen von so vielen Dateien, also der reinen Strings, ging bei mir auch recht schnell. Zum zweiten Vorschlag: Dieser scheint eher zu passen. Die Anwendung bleibt interaktiv, was sowieso schon so mein Problem war, nur die Geschwindigkeit des Größe-Auslesens der Dateien, wird ja nicht besser. Allerdings wird das natürlich schön durch das stückchenweise hinzufügen besser "vertuscht" ;-) Allerdings liegt hier mein Problem noch in dem genauen Verständnis der Delegates/Invokes - hier fehlen mir halt noch die Basics, welche ich mir dann wohl noch selbst anlesen werden muss. Aber mal allgemein gefragt: Wieso geht das denn im normalen Windows Explorer so fix? Da merkt man ja fast keine Verzögerung? MfG AnDi_P Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Mcolli Geschrieben 11. März 2010 Teilen Geschrieben 11. März 2010 Aber mal allgemein gefragt: Wieso geht das denn im normalen Windows Explorer so fix? Da merkt man ja fast keine Verzögerung? Wie gesagt, ich konnte den Performance-Verlust zuhause nicht nachvollziehen. Mein Rechner ist aber auch neu und von mir konfiguriert worden, so ist u.a. die Fragmentation der Dateien bei annährend 0% Allgein gesehen nutzt Du ja die Klassen aus dem .NetFramework (System.IO - Namespace). Diese bieten Dir ja High-Level Schnittstellen um aufs Dateisystem der Festplatte zuzgreifen. Meine Vermutung ist die, das Windows intern eben nicht das .NET Framework zugreift sondern direkt den MFT ("Master File Table" - also das Inhaltsverzeichnis bei NTFS-konformen Platten) ausliest und gegenbenfalls diesen indeziert. Diese Vermutung begründet sich dadadurch, dass die Fähigkeit von einer Festplatte zu lesen bzw auf eine Festplatte zu schreiben heute wohl eines der ersten Sachen ist die man so implementieren muss wenn man ein Betriebsystem schreibt. Das ist wie gesagt nur ne Vermutung, die ich aufgrund meines Allgemeinwissens aufstelle, mir fehlt da die Muße mich genauer schlau zu machen, da ich der Ansicht bin man sollte System.IO nutzen und wenns zu lahm ist muss man das vor dem Benutzer seiner Software verschleiern oder Ihn mit tollen Warteanimationen bei Laune halten. Eine Andere gute Sache um lange Ladezeiten zu kaschieren ist "Paging"... empfielt sich aber eher beim Umgang mit Datenbanken .... Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
AnDi_P Geschrieben 15. März 2010 Autor Teilen Geschrieben 15. März 2010 Alles klar, vielen Dank für die Infos! Sollte sonst noch jemand irgendwelche Ideen haben, kann er sie gerne mitteilen MfG AnDi_P Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.