Zum Inhalt springen

C#: Dateigröße auslesen (langsam)


AnDi_P

Empfohlene Beiträge

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

Link zu diesem Kommentar
Auf anderen Seiten teilen

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

Link zu diesem Kommentar
Auf anderen Seiten teilen

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?

Link zu diesem Kommentar
Auf anderen Seiten teilen

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 von Mcolli
Link zu diesem Kommentar
Auf anderen Seiten teilen

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

Link zu diesem Kommentar
Auf anderen Seiten teilen

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

Link zu diesem Kommentar
Auf anderen Seiten teilen

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 ....

Link zu diesem Kommentar
Auf anderen Seiten teilen

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.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...