Benutzer mit den meisten Antworten
Dateien rekursiv, abhängig von der Extension löschen

Frage
-
http://www1.minpic.de/bild_anzeigen.php?id=117412&key=31476149&ende
Hallo,
ich suche folgendes:
Eine XML Datei mit Extensions wird eingelesen.
Ein aktiver Ordner wird ausgewählt. Das Programm merkt sich das.
Evtl. der Vorschlag von Frank mit UserSettings.Checkbox - Unterordner auch
Button Start, alle Dateien werden gelöscht.
Hat jemand eine praktikable Lösung?
So eine Art BatchDatei
del /s CPP_Pr\*.ncb > C:\_IDX\Delete.txt
del /s CPP_Pr\*.pch > C:\_IDX\Delete.txt
del /s CPP_Pr\*.obj > C:\_IDX\Delete.txt
del /s CPP_Pr\*.sbr > C:\_IDX\Delete.txt
del /s CPP_Pr\*.bsc > C:\_IDX\Delete.txt
del /s CPP_Pr\*.pdb > C:\_IDX\Delete.txt
del /s CPP_Pr\*.ilk > C:\_IDX\Delete.txt
del /s CPP_Pr\*.idb > C:\_IDX\Delete.txt
del /s CPP_Pr\*.tlh > C:\_IDX\Delete.txt
del /s CPP_Pr\*.tli > C:\_IDX\Delete.txtGrüße Andreas
Antworten
-
Hallo Andreas,
bezüglich: 0x80 heißt einfach, es könnten nur 128 geschrieben werden, oder?
Ja, es ist eine hexadezimale Konstante. Und es wäre hier (das nur Testcode) nicht notwendig.
Durch die Vorgabe der Kapazität eines StringBuilders hat man ein weniger Pufferallokationen,
wenn man bereits eine größere Länge erwartet, was dem Garbage Collector weniger Arbeit macht.
Relevant das hier letztendlich nicht.Und es ist wie gesagt nur Beispielcode um den Einsatz der Methode zu zeigen.
Bezüglich des Löschen in den Papierkorb:
Wenn Du die Liste weiter bearbeiten möchtest, so könntest Du die gelieferte Liste
zum Beispiel an eine CheckedListBox übergeben.
(Wenn Du damit Probleme hast, oder einen anderen Weg gehen möchtest,
mache bitte einen neuen Thread auf, dieser hier wird langsam unübersichtlich ;-)
Ich habe hier zwar mittlerweile grundsätzlich funktionierenden Code.
Durch die etwas krude Implementation (wie bei der Shell nicht ganz unüblich ;-)
würde der wesentlich mehr Tests erfordern, um für mich als "produktiv" gelten
zu können - und die Zeit habe ich derzeit nicht.
Ich würde Dir empfehlen - wie auch im Pinvoke Link erwähnt,
auf die bei Visual Basic schon vorhandene Funktionalität zurückzugreifen.Dazu mußt Du die Microsoft.VisualBasic.dll in die Projekt Referenzen aufnehmen.
Dann im Kopf einfügenusing Microsoft.VisualBasic.FileIO;
und anstatt eines File.Delete:
FileSystem.DeleteFile(filename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
Für mehr siehe FileSystem.DeleteFile
Und wäre eine der wenigen Stellen, wo die Visual Basic My-Erweiterungen, zu denen es gehört,
dem Rest der BCL ein wenig voraus hat (in die man keine Windows spezifischen Dinge einbauen wollte).Ich hatte Deinen Code zwar nur überflogen (um obiges nachzuvollziehen).
Auffiel die Prüfung via File.Exists vor dem File.Delete . Das ist nicht notwendig,
da File.Delete stillschweigend zurückkehrt, wenn die Datei nicht existiert,
siehe die Dokumentation dazu.Zum Schluß noch einmal die Empfehlung:
Lies (bzw. überflieg) die Dokumentation jeder neuen Klasse und Methode.
Das mag anfangs etwas aufhalten, auf Dauer lernt man aber am schnellsten -
zumindest für mich gilt das.
Auch wenn Du bereits Erfahrung in C(++) hast (hatte ich auch):
.NET ist an vielen Stellen anders konzipiert - im Vergleich zum Windows-API
oder Frameworks wie dem MFC/STL usw. - und gleiche oder ähnliche Klassen-
und/oder Methodennamen arbeiten nicht unbedingt so wie man (anfangs) erwartet.Arbeitet man länger damit, erkennt man (meist) den Sinn dahinter.
So mag File.Delete als typisches Beispiel gelten. Um keine unnötige
Fehlerbehandlung zu erfordern, die den Code nur unübersichtlich gestalten,
wird dort das Fehlen der Datei nicht als Ausnahmebedingung betrachtet.
Und nur Dinge wie ungültige Verzeichnisse (es fehlt mehr als der nur die Datei)
lösen Ausnahmen aus.Gruß Elmar
Zum @Thorsten übergebe ich das Wort an Thorsten ;-)
- Als Antwort markiert Thorsten DörflerEditor Sonntag, 25. Juli 2010 16:46
-
Hallo Andreas,
als Alternative habe ich meine Vorschläge/Beispiele mal zu einem kleinen, lauffähigen Projekt zusammengesteckt.
Gehe damit wie folgt vor:
- Erstelle ein neues Windows-Forms-Projekt, und öffen die code-Ansicht von Form1.
- Lösche dort allen Code und kopiere den ersten Codeblock von hier dort hinein.
- Öffne die Datei Form1.Designer.cs und lösche dort allen Code.
- Kopiere dann den zweiten Codeblock dort hinein.
- Öffne die Datei Programm.cs, lösche den Code und kpoiere den CodeBlock 3 dort hinein.
- starte das Projekt.
Das Ganze ist lauffähig, die Deleteanweisung ist aber noch auskommentiert, do dass es so als Simulation läuft.
Lauffähig heißt nicht unbedingt Fehlerfrei, es soll Dir quasi das Prinzip näherbringen. Änderungen, bessere Fehlerbehandlung usw, wirst Du schon im Laufe der Zeit dann einfügen.
###################
Codeblock 1, Form1.cs:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; namespace DeleteFilesByExtension { public partial class Form1 : Form { private List<FileInfo> _fList = null; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { if (this.folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.label1.Text = this.folderBrowserDialog1.SelectedPath; this.button2.Enabled = this.button3.Enabled = true; } } private void button2_Click(object sender, EventArgs e) { bool doSubDirectories = this.checkBox1.Checked; string[] Extensions = this.textBox1.Text.Split(new string[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries); if (Extensions.Length > 0) { this.listBox1.Items.Clear(); DirectoryInfo dir = new DirectoryInfo(this.label1.Text); List<FileInfo> fList = new List<FileInfo>(); DoTheWork(dir, fList, Extensions, doSubDirectories); foreach (FileInfo FI in fList) this.listBox1.Items.Add(FI.FullName); this._fList = fList; if (this._fList.Count > 0) this.button3.Enabled = true; } } private void DoTheWork(DirectoryInfo dir, List<FileInfo> fList, string[] Extensions, bool doSubdirectories) { //Breitensuche (für Tiefensuche // Part "//Rekursion" an den Anfang der Routine stellen.) if (Extensions.Length > 0) { for (int j = 0; j < Extensions.Length; j++) { FileInfo[] files = dir.GetFiles(Extensions[j].Replace("\"", "").Trim()); for (int i = 0; i < files.Length; i++) fList.Add(files[i]); } } //Rekursion if (doSubdirectories) { DirectoryInfo[] dirs = dir.GetDirectories(); for (int i = 0; i < dirs.Length; i++) { try { DoTheWork(dirs[i], fList, Extensions, doSubdirectories); } catch { } } } } private void button3_Click(object sender, EventArgs e) { if (this._fList != null) { foreach (FileInfo FI in _fList) { try { //Kommentarzeichen entfernen, dann wird *wirklich* gelöscht //FI.Delete(); } catch { } } this.listBox1.Items.Clear(); this.button3.Enabled = false; } } } }
###################
CodeBlock 2, Form1.Designer.cs
namespace DeleteFilesByExtension { partial class Form1 { /// <summary> /// Erforderliche Designervariable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Verwendete Ressourcen bereinigen. /// </summary> /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Vom Windows Form-Designer generierter Code /// <summary> /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// </summary> private void InitializeComponent() { this.listBox1 = new System.Windows.Forms.ListBox(); this.button1 = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.button2 = new System.Windows.Forms.Button(); this.button3 = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); this.label2 = new System.Windows.Forms.Label(); this.checkBox1 = new System.Windows.Forms.CheckBox(); this.SuspendLayout(); // // listBox1 // this.listBox1.FormattingEnabled = true; this.listBox1.HorizontalScrollbar = true; this.listBox1.Location = new System.Drawing.Point(13, 13); this.listBox1.Name = "listBox1"; this.listBox1.Size = new System.Drawing.Size(653, 550); this.listBox1.TabIndex = 0; // // button1 // this.button1.Location = new System.Drawing.Point(695, 81); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(129, 23); this.button1.TabIndex = 1; this.button1.Text = "Verzeichnis wählen"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // label1 // this.label1.Location = new System.Drawing.Point(695, 26); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(213, 41); this.label1.TabIndex = 2; this.label1.Text = "Hallo"; // // button2 // this.button2.Enabled = false; this.button2.Location = new System.Drawing.Point(698, 487); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(129, 23); this.button2.TabIndex = 3; this.button2.Text = "Dateien auflisten"; this.button2.UseVisualStyleBackColor = true; this.button2.Click += new System.EventHandler(this.button2_Click); // // button3 // this.button3.Enabled = false; this.button3.Location = new System.Drawing.Point(698, 540); this.button3.Name = "button3"; this.button3.Size = new System.Drawing.Size(129, 23); this.button3.TabIndex = 4; this.button3.Text = "Dateien löschen"; this.button3.UseVisualStyleBackColor = true; this.button3.Click += new System.EventHandler(this.button3_Click); // // textBox1 // this.textBox1.Location = new System.Drawing.Point(76, 585); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(751, 20); this.textBox1.TabIndex = 5; this.textBox1.Text = "*.ncb, *.obj, *.sbr, *.bsc, *.pdb, *.ilk, *.idb, *.tlh, *.tli"; // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(12, 588); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(58, 13); this.label2.TabIndex = 6; this.label2.Text = "Extensions"; // // checkBox1 // this.checkBox1.AutoSize = true; this.checkBox1.Checked = true; this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; this.checkBox1.Location = new System.Drawing.Point(695, 123); this.checkBox1.Name = "checkBox1"; this.checkBox1.Size = new System.Drawing.Size(116, 17); this.checkBox1.TabIndex = 7; this.checkBox1.Text = "Unterverzeichnisse"; this.checkBox1.UseVisualStyleBackColor = true; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(920, 617); this.Controls.Add(this.checkBox1); this.Controls.Add(this.label2); this.Controls.Add(this.textBox1); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.label1); this.Controls.Add(this.button1); this.Controls.Add(this.listBox1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D; this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.ListBox listBox1; private System.Windows.Forms.Button button1; private System.Windows.Forms.Label label1; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button3; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Label label2; private System.Windows.Forms.CheckBox checkBox1; } }
######################
CodeBlock3, Programm.cs
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace DeleteFilesByExtension { static class Program { /// <summary> /// Der Haupteinstiegspunkt für die Anwendung. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }
Viele Grüße,
Thorsten
- Als Antwort markiert Thorsten DörflerEditor Sonntag, 25. Juli 2010 16:45
Alle Antworten
-
Hallo,
Du meinst, alle Dateien in dem ausgewählten Verzeichnis (Unterverzeichnisse optional) mit der/den gewählten Dateinamenserweitrungen sollen gelöscht werden?
Dazu rekursiv durch die Ordner navigieren (beim Löschen empfiehlt es sich von unten her in der Verzeichnisstruktur anzufangen, da man evtl. leere Ordner auch gleich entfernen will) - und in den Ordnern jeweils eine Schleife über die Dateien laufen lassen und die entsprechenden löschen.
Schaue Dir dazu bitte den Namensraum System.IO an, insbesondere hier das DirectoryInfo Objekt, sowie das FileInfo Objekt, mit beiden kannst Du diese Aufgabe bequem lösen.
Viele Grüße
Thorsten
-
Hallo Thorsten,
>Du meinst, alle Dateien in dem ausgewählten Verzeichnis (Unterverzeichnisse optional) mit >der/den gewählten Dateinamenserweitrungen sollen gelöscht werden?
ja genau.
Ok ich schaus mir an.
Falls du noch ein Beispiel hast kannst es gerne veröffentlichen.
oder
Falls du noch ein Beispielkennst (CodeProject, CodeGuru etc.)
kannst es gerne veröffentlichen.
Schönes Wochenende Andreas
-
Hallo,
ein einfaches Beispiel für Tiefen-Rekursion: Verweis zu System.IO (using System.IO) hinzufügen
private void button1_Click(object sender, EventArgs e) { bool doSubDirectories = true; DirectoryInfo dir = new DirectoryInfo(@"Pfad\zu\Verzeichnis"); List<FileInfo> fList = new List<FileInfo>(); DoTheWork(dir, fList, doSubDirectories); MessageBox.Show(fList.Count.ToString()); } private void DoTheWork(DirectoryInfo dir, List<FileInfo> fList, bool doSubdirectories) { if (doSubdirectories) { DirectoryInfo[] dirs = dir.GetDirectories(); for (int i = 0; i < dirs.Length; i++) { try { DoTheWork(dirs[i], fList, doSubdirectories); } catch { } } } FileInfo[] files = dir.GetFiles("*.txt"); for (int i = 0; i < files.Length; i++) fList.Add(files[i]); }
Pfad zum Verzeichnis und SearchPattern bei dir.GetFiles() anpassen.
Ich wäre aber sehr vorsichtig mit dem Löschen von Dateien während der Test-/Enstehungs-phase des Programmes. Lass Dir lieber erst einmal nur die Namen, oder Pfade zu den gefundenen Dateien ausgeben. Denn löschen hier heißt *löschen*, kein Papierkorb, kein doppelter Boden, kein gar nichts.
Viele Grüße
Thorsten
-
Ich wäre aber sehr vorsichtig mit dem Löschen von Dateien während der Test-/Enstehungs-phase des Programmes. Lass Dir lieber erst einmal nur die Namen, oder Pfade zu den gefundenen Dateien ausgeben. Denn löschen hier heißt *löschen*, kein Papierkorb, kein doppelter Boden, kein gar nichts.
Hallo, ja genau;-)
Deshalb habe ich nachgefragt, sonst sind die Dateien weg, da es leider nicht in den Papierkorb geht.
Grüße Andreas
-
Hallo,
doch nicht so einfach. Mehrere Dateien scheint nicht zu gehen.
Wie macht man es richtig?
Danke im Voraus.
Andreas
<span style="color:blue">string</span> searchPattern = <span style="color:#a31515">"*.ncb"</span>;<span style="color:green">// Tilde geht auch nicht. | *.obj"; //,*.obj,*.sbr,*.bsc,*.pdb,*.ilk,*.idb,*.tlh,*.tli";</span>
const string CR = "\n"; private void btnDeleteFiles_Click(object sender, EventArgs e) { bool doSubDirectories = true; DirectoryInfo dir = new DirectoryInfo(@"c:\Test\Regression\"); List<FileInfo> fList = new List<FileInfo>(); DoTheWork(dir, fList, doSubDirectories); string strListFiles = ""; int z = 0; foreach (FileInfo file in fList) { if ( z == 0) strListFiles = "Anzahl Dateien " + fList.Count.ToString() + CR + file.FullName + CR; else strListFiles += file.FullName + CR; z++; } MessageBox.Show(strListFiles); switch ( MessageBox.Show( "Möchten Sie die Dateien löschen?", "Dateien", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) { case DialogResult.Yes: // "Ja" wurde geklickt foreach (FileInfo file in fList) { try { file.Delete(); } catch (Exception eFile) { // } } break; case DialogResult.No: // "Nein" wurde geklickt break; } } private void DoTheWork(DirectoryInfo dir, List<FileInfo> fList, bool doSubdirectories) { if ( doSubdirectories ) { DirectoryInfo[] dirs = dir.GetDirectories(); for (int i = 0; i < dirs.Length; i++) { try { DoTheWork(dirs[i], fList, doSubdirectories); } catch { } } } //del /s _TEST34\*.ncb > C:\_TSZ\Delete.txt //del /s _TEST34\*.ncb > C:\_TSZ\Delete.txt //del /s _TEST34\*.obj > C:\_TSZ\Delete.txt //del /s _TEST34\*.sbr > C:\_TSZ\Delete.txt //del /s _TEST34\*.bsc > C:\_TSZ\Delete.txt //del /s _TEST34\*.pdb > C:\_TSZ\Delete.txt //del /s _TEST34\*.ilk > C:\_TSZ\Delete.txt //del /s _TEST34\*.idb > C:\_TSZ\Delete.txt //del /s _TEST34\*.tlh > C:\_TSZ\Delete.txt //del /s _TEST34\*.tli > C:\_TSZ\Delete.txt http://msdn.microsoft.com/de-de/library/ms143327.aspx string searchPattern = "*.ncb";// | *.obj"; //,*.obj,*.sbr,*.bsc,*.pdb,*.ilk,*.idb,*.tlh,*.tli"; //string[] s1 = dir.GetFiles("*.ncb"); //string[] s2 = dir.GetFiles("*.obj"); //string pattern = "[~#%&*{}/<>?|\"-]+"; //Regex regEx = new Regex(pattern); //string[] fileDrive = Directory.GetFiles(retPath, "*.*", SearchOption.AllDirectories); //files = System.IO.Directory.GetFiles(searchDirectory, "*.ex e"); //fileList.AddRange(files); //files = System.IO.Directory.GetFiles(searchDirectory, "*.dl l"); //fileList.AddRange(files); searchPattern = "*.ncb"; AddFiles(dir, fList, searchPattern); searchPattern = "*.obj"; AddFiles(dir, fList, searchPattern); searchPattern = "*.sbr"; AddFiles(dir, fList, searchPattern); searchPattern = "*.bsc"; AddFiles(dir, fList, searchPattern); searchPattern = "*.pdb"; AddFiles(dir, fList, searchPattern); searchPattern = "*.ilk"; AddFiles(dir, fList, searchPattern); searchPattern = "*.idb"; AddFiles(dir, fList, searchPattern); searchPattern = "*.tlh"; AddFiles(dir, fList, searchPattern); searchPattern = "*.tli"; AddFiles(dir, fList, searchPattern); } private void AddFiles(DirectoryInfo dir, List<FileInfo> fList, string searchPattern) { FileInfo[] files = dir.GetFiles(searchPattern); for (int i = 0; i < files.Length; i++) fList.Add(files[i]); // fList.AddRange(files); } }
-
Hallo Andreas,
Was genau funktioniert denn nicht?
Hier ein kleines Beispiel mit Datei-Erweiterungsliste. Eine Form, einen Button drauf und eine ListBox (die ein bischen größer ziehen): Achja, hier ist die Rekursion als Breitensuche implementiert, das heißt, man bekommt die Sicht auf die Verzeichnisstruktur von "oben", ist z.B. gut zum Erstellen von Dateilisten.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; namespace fdsdasfs { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { bool doSubDirectories = true; DirectoryInfo dir = new DirectoryInfo(@"Pfad\zu\Verzeichnis"); List<FileInfo> fList = new List<FileInfo>(); string[] Extensions = new string[] { "*.txt", "*.jpg", "*.cs", "*.png", "*.html" }; DoTheWork(dir, fList, Extensions, doSubDirectories); foreach (FileInfo FI in fList) this.listBox1.Items.Add(FI.FullName); } private void DoTheWork(DirectoryInfo dir, List<FileInfo> fList, string[] Extensions, bool doSubdirectories) { //Breitensuche (für Tiefensuche // Part "//Rekursion" an den Anfang der Routine stellen.) if (Extensions.Length > 0) { for (int j = 0; j < Extensions.Length; j++) { FileInfo[] files = dir.GetFiles(Extensions[j]); for (int i = 0; i < files.Length; i++) fList.Add(files[i]); } } //Rekurion if (doSubdirectories) { DirectoryInfo[] dirs = dir.GetDirectories(); for (int i = 0; i < dirs.Length; i++) { try { DoTheWork(dirs[i], fList, Extensions, doSubdirectories); } catch { } } } } } }
Sag halt Mal, was nicht funktioniert.
Viele Grüße,
Thorsten
-
achja, hier ist die Rekursion als Breitensuche implementiert, das heißt, man bekommt die Sicht auf die Verzeichnisstruktur von "oben", ist z.B. gut zum Erstellen von Dateilisten.
//Breitensuche (für Tiefensuche // Part "//Rekursion" an den Anfang der Routine stellen.)
Sag halt Mal, was nicht funktioniert.
Hallo Thorsten,
Danke ja schon richtig erkannt, sieht besser aus.
string searchPattern = "*.ncb";
// | *.obj"; //,*.obj,*.sbr,*.bsc,*.pdb,*.ilk,*.idb,*.tlh,*.tli";
//string[] s1 = dir.GetFiles("*.ncb");Was nicht funktionierte ist, wenn ich mehrere unterschiedliche extension habe.
http://www.codeguru.com/forum/showthread.php?t=344379
hier wird noch die RegEx erwähnt, aber wie's konkret gemacht wird fehlt.
http://www.mycsharp.de/wbb2/thread.php?threadid=14007&hilight=getfiles+regex
//Breitensuche (für Tiefensuche
// Part "//Rekursion" an den Anfang der Routine stellen.)
Das habe ich nicht richtig verstanden.Kannst du zur Breitensuche noch was sagen? Wie du das konkret meinst.
Grüße Andreas
-
Hallo,
Breitensuche =
1. Gewünschte Operationen der Methode ausführen, dann
2. der rekursive Methodenaufruf.
Tiefensuche =
1. Rekursives Aufrufen der Methode, dann
2. gewünschte OPerationen der Methode ausführen
Also konkret, wenn Du zuerst die DateiInfos in die Liste schreibst und die Methode sich danach selbst wieder aufruft, dann werden ja immer zuerst die Infos aufgelistet für das jeweilige Verzeichnis und dann das nächste Verzeichnis "angewählt", so dass die Struktur zuerst in der Breite "abgesucht" wird.
Wenn sich die Methode hingegen zuerst immer wieder selbst aufruft, bis keine Subdirectories mehr zu finden sind und dann die DateiInfos auflistet, dann fängt die Ausgabe/Operationen ja unten in der Struktur an und die Navigation geht dann praktisch Stück für Stück nach oben, so dass hier dann eben von Tiefensuche gesprochen werden kann.
Stichworte hierzu wären: Bäume, Graphentheorie etc.
http://de.wikipedia.org/wiki/Breitensuche
http://de.wikipedia.org/wiki/Tiefensuche
siehe vor allem die Bilder dort.
Es gab auch ein paar MSDN-Webcasts zu dem Thema, die auch Einsteigern verständlich die Ideen/Grundlagen vermitteln können:
http://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032301564
Viele Grüße,
Thorsten
-
Was nicht funktionierte ist, wenn ich mehrere unterschiedliche extension habe.
http://www.codeguru.com/forum/showthread.php?t=344379
hier wird noch die RegEx erwähnt, aber wie's konkret gemacht wird fehlt.
http://www.mycsharp.de/wbb2/thread.php?threadid=14007&hilight=getfiles+regex
Naja, die Menge der Extension scheint ja überschaubar zu sein, so dass Du die ruhig alle nacheinander für die Liste abarbeiten kannst.
In meinem Beispiel lief das so ab:
if (Extensions.Length > 0) { for (int j = 0; j < Extensions.Length; j++) { FileInfo[] files = dir.GetFiles(Extensions[j]); for (int i = 0; i < files.Length; i++) fList.Add(files[i]); } }
Zu Regular Expressions mal wieder die Wiki:http://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck
Wie gesagt, nicht unbedingt nötig, aber recht "elegant".
Viele Grüße,
Thorsten
-
Hallo Andreas,
ich hatte im letzten Jahr mal für Visual Basic einen FileHelper zur Suche
über mehrere Unterverzeichnisse und optional mehrere Erweiterungen erstellt.Hier die C# Inkarnation dazu und zusätzlich eine DeleteFileRecursive Methode,
die die gefundenen Dateien löscht.
Wenn Du in den Papierkorb löschen willst, wäre das via SHFILEOPSTRUCT zu implementieren.
Bei Bedarf kann ich das morgen nachreichen, heute fehlt die Zeit fürs Testen.using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; public static class FileHelper { /// <summary> /// Erstellt eine Dateiliste rekursiv. /// </summary> /// <remarks> /// Es kann nach mehreren Mustern gesucht werden, die durch ";" getrennt werden. /// Dateien und Verzeichnisse auf die kein Zugriff besteht werden ausgelassen. /// </remarks> /// <param name="path">Der Ausgangspfad.</param> /// <param name="searchPatterns">Eine Liste von Suchmustern</param> /// <returns>eine List<String></returns> public static List<string> FindFilesRecursive(string path, string searchPatterns) { if (path == null) throw new ArgumentNullException("path"); path = path.Trim(); if (path.Length == 0) throw new ArgumentException("path"); if (string.IsNullOrEmpty(searchPatterns)) throw new ArgumentNullException("searchPatterns"); // Anfangspfad vorgeben (hier mögliche Ausnahme) path = Path.GetFullPath(path); List<string> fileList = new List<string>(); List<string> searchPatternList = new List<string>(); foreach (string searchPattern in searchPatterns.Split(';')) { var pattern = searchPattern.Trim(); if (pattern.Length > 0) { searchPatternList.Add(pattern); } } if (searchPatternList.Count != 0) { Stack<string> directoryStack = new Stack<string>(); directoryStack.Push(path); // Verzeichnisse rekursiv (via Stack) durchlaufen while (directoryStack.Count > 0) { string directory = directoryStack.Pop(); try { // Durchlaufen aller Suchmuster foreach(var pattern in searchPatternList) fileList.AddRange(Directory.GetFiles(directory, pattern)); } catch (UnauthorizedAccessException) { Debug.WriteLine("No File Access " + directory); } try { // Einfügen der Unterverzeichnisse in den Stack foreach (string subDirectory in Directory.GetDirectories(directory)) directoryStack.Push(subDirectory); } catch (UnauthorizedAccessException) { Debug.WriteLine("No Directory Access " + directory); } } // und sortieren fileList.Sort(StringComparer.OrdinalIgnoreCase); } return fileList; } /// <summary> /// Löscht eine Dateiliste rekursiv. /// </summary> /// <remarks> /// Es kann nach mehreren Mustern gesucht werden, die durch ";" getrennt werden. /// Dateien und Verzeichnisse auf die kein Zugriff besteht werden ausgelassen. /// </remarks> /// <param name="path">Der Ausgangspfad.</param> /// <param name="searchPatterns">Eine Liste von Suchmustern</param> /// <returns>eine List<String></returns> public static void DeleteFilesRecursive(string path, string searchPatterns) { var fileNameList = FindFilesRecursive(path, searchPatterns); foreach (var fileName in fileNameList) { try { File.Delete(fileName); } catch (UnauthorizedAccessException) { Debug.WriteLine("No access " + fileName); } catch (IOException) { Debug.WriteLine("File in use " + fileName); } } } /// <summary>Kleiner Test zu FindFilesRecursive</summary> [Conditional("DEBUG")] internal static void FindFileRecursiveTest() { string path = "E:"; string searchPatterns = "*.mp3;*.wav;*.wmv;*.wma"; List<string> fileList = FindFilesRecursive(path, searchPatterns); StringBuilder builder = new StringBuilder(0x80); foreach (string name in fileList) { builder.AppendLine(name); } File.WriteAllText(@"F:\fileslist.txt", builder.ToString()); } }
RegEx ginge zwar auch, dabei müsste man aber die Muster den Regeln
von RegEx-Mustern anpassen, die anders sind (? wäre . usw.).
Das lohnt aber nur wenn es riesige Dateianzahlen werden.
Zum Aufräumen von Compilerüberbleibseln tut es obige Methode alle Male ;-)Gruß Elmar
-
Hier die C# Inkarnation dazu und zusätzlich eine DeleteFileRecursive Methode,
die die gefundenen Dateien löscht.
Wenn Du in den Papierkorb löschen willst, wäre das via SHFILEOPSTRUCT zu implementieren.
Bei Bedarf kann ich das morgen nachreichen, heute fehlt die Zeit fürs Testen.Hallo Elmar,
gerne doch.
Danke im voraus.
Grüße Andreas
-
Hallo Elmar,
prinzipiell würde es ja schon reichen.
Ich will ja nur die unnötigen Compilerdateien gezielt löschen.
Wenn es mehrere Ansätze gibt, bin ich gerne lernfähig, man sieht die Unterschiede,
nächstes mal kann man es vielleicht schon selber.
Auch meine Recherche mit der RegEx ist auch nicht ganz einfach, wenn man es noch nie gemacht hat.
D.h. wenn du noch was hast, gerne doch.
Wenn es zunächst in der Papierkorb geht, umso besser, falls eben was schief geht,
kann man es rückgängig machen.
Also klares JA.
Danke.
Grüße Andreas
-
Hallo,
also zusammenfassend läuft nicht alles optimal.
Ich habe einfach mal ein Projekt gemacht.Was geht.
meine erster Versuch, jedoch nicht optimal gelöst.
Die anderen gehen nicht.
Siehe u.a.
Bild.
http://www1.minpic.de/bild_anzeigen.php?id=117998&key=54794025&endeProjekt
http://www.materialordner.de/OMgREBejOrtIbrtKUZPHEIVe2jYJYUm.htmlDanke für weitere Hilfe.
> http://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032301564
@Thorsten, der Link ist gut, kannte ich nicht.
Grüße Andreas
-
Hallo,
zu Deinem Bild:
Füge am Anfang der Form
using System.Diagnostics;
hinzu:
http://msdn.microsoft.com/de-de/library/system.diagnostics.conditionalattribute(v=VS.90).aspx
und:
http://msdn.microsoft.com/de-de/library/4xssyw96(VS.90).aspx
Viele Grüße,
Thorsten
-
Hallo Andreas,
Thorsten hat Dir bereits einige Tipps gegeben, deswegen nur kurz.
Die FileHelper Methoden erwarten eine durch ";" separarierte Liste
und zumindest im Download Code hast Du ein "," verwendet.
Damit wird es somit nicht funktionieren.Ein Tipp zum Finden von Namespace Deklarationen:
Wenn ein Namespace nicht bereits als using Anweisung vorhanden ist,
so kannst Du Dir einen Vorschlag über Intellisense abrufen, in dem Du
STRG+. (Punkt) drückst, wenn Du Dich auf dem unterkringelten Namen
befindest. Sofern die benötigte Assembly bereits eingebunden ist,
gibt Dir Intellisense die Möglichkeit, entweder die using Anweisung
einzufügen oder den Namen um den Namespace zu ergänzen.Auch empfiehlt sich am Anfang der intensive Gebrauch der <F1> Taste
um sich mit unbekannten Klassen bekannt zu machen.Gruß Elmar
-
Hallo Andreas,
als Alternative habe ich meine Vorschläge/Beispiele mal zu einem kleinen, lauffähigen Projekt zusammengesteckt.
Gehe damit wie folgt vor:
- Erstelle ein neues Windows-Forms-Projekt, und öffen die code-Ansicht von Form1.
- Lösche dort allen Code und kopiere den ersten Codeblock von hier dort hinein.
- Öffne die Datei Form1.Designer.cs und lösche dort allen Code.
- Kopiere dann den zweiten Codeblock dort hinein.
- Öffne die Datei Programm.cs, lösche den Code und kpoiere den CodeBlock 3 dort hinein.
- starte das Projekt.
Das Ganze ist lauffähig, die Deleteanweisung ist aber noch auskommentiert, do dass es so als Simulation läuft.
Lauffähig heißt nicht unbedingt Fehlerfrei, es soll Dir quasi das Prinzip näherbringen. Änderungen, bessere Fehlerbehandlung usw, wirst Du schon im Laufe der Zeit dann einfügen.
###################
Codeblock 1, Form1.cs:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; namespace DeleteFilesByExtension { public partial class Form1 : Form { private List<FileInfo> _fList = null; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { if (this.folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.label1.Text = this.folderBrowserDialog1.SelectedPath; this.button2.Enabled = this.button3.Enabled = true; } } private void button2_Click(object sender, EventArgs e) { bool doSubDirectories = this.checkBox1.Checked; string[] Extensions = this.textBox1.Text.Split(new string[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries); if (Extensions.Length > 0) { this.listBox1.Items.Clear(); DirectoryInfo dir = new DirectoryInfo(this.label1.Text); List<FileInfo> fList = new List<FileInfo>(); DoTheWork(dir, fList, Extensions, doSubDirectories); foreach (FileInfo FI in fList) this.listBox1.Items.Add(FI.FullName); this._fList = fList; if (this._fList.Count > 0) this.button3.Enabled = true; } } private void DoTheWork(DirectoryInfo dir, List<FileInfo> fList, string[] Extensions, bool doSubdirectories) { //Breitensuche (für Tiefensuche // Part "//Rekursion" an den Anfang der Routine stellen.) if (Extensions.Length > 0) { for (int j = 0; j < Extensions.Length; j++) { FileInfo[] files = dir.GetFiles(Extensions[j].Replace("\"", "").Trim()); for (int i = 0; i < files.Length; i++) fList.Add(files[i]); } } //Rekursion if (doSubdirectories) { DirectoryInfo[] dirs = dir.GetDirectories(); for (int i = 0; i < dirs.Length; i++) { try { DoTheWork(dirs[i], fList, Extensions, doSubdirectories); } catch { } } } } private void button3_Click(object sender, EventArgs e) { if (this._fList != null) { foreach (FileInfo FI in _fList) { try { //Kommentarzeichen entfernen, dann wird *wirklich* gelöscht //FI.Delete(); } catch { } } this.listBox1.Items.Clear(); this.button3.Enabled = false; } } } }
###################
CodeBlock 2, Form1.Designer.cs
namespace DeleteFilesByExtension { partial class Form1 { /// <summary> /// Erforderliche Designervariable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Verwendete Ressourcen bereinigen. /// </summary> /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Vom Windows Form-Designer generierter Code /// <summary> /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// </summary> private void InitializeComponent() { this.listBox1 = new System.Windows.Forms.ListBox(); this.button1 = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.button2 = new System.Windows.Forms.Button(); this.button3 = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); this.label2 = new System.Windows.Forms.Label(); this.checkBox1 = new System.Windows.Forms.CheckBox(); this.SuspendLayout(); // // listBox1 // this.listBox1.FormattingEnabled = true; this.listBox1.HorizontalScrollbar = true; this.listBox1.Location = new System.Drawing.Point(13, 13); this.listBox1.Name = "listBox1"; this.listBox1.Size = new System.Drawing.Size(653, 550); this.listBox1.TabIndex = 0; // // button1 // this.button1.Location = new System.Drawing.Point(695, 81); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(129, 23); this.button1.TabIndex = 1; this.button1.Text = "Verzeichnis wählen"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // label1 // this.label1.Location = new System.Drawing.Point(695, 26); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(213, 41); this.label1.TabIndex = 2; this.label1.Text = "Hallo"; // // button2 // this.button2.Enabled = false; this.button2.Location = new System.Drawing.Point(698, 487); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(129, 23); this.button2.TabIndex = 3; this.button2.Text = "Dateien auflisten"; this.button2.UseVisualStyleBackColor = true; this.button2.Click += new System.EventHandler(this.button2_Click); // // button3 // this.button3.Enabled = false; this.button3.Location = new System.Drawing.Point(698, 540); this.button3.Name = "button3"; this.button3.Size = new System.Drawing.Size(129, 23); this.button3.TabIndex = 4; this.button3.Text = "Dateien löschen"; this.button3.UseVisualStyleBackColor = true; this.button3.Click += new System.EventHandler(this.button3_Click); // // textBox1 // this.textBox1.Location = new System.Drawing.Point(76, 585); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(751, 20); this.textBox1.TabIndex = 5; this.textBox1.Text = "*.ncb, *.obj, *.sbr, *.bsc, *.pdb, *.ilk, *.idb, *.tlh, *.tli"; // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(12, 588); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(58, 13); this.label2.TabIndex = 6; this.label2.Text = "Extensions"; // // checkBox1 // this.checkBox1.AutoSize = true; this.checkBox1.Checked = true; this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; this.checkBox1.Location = new System.Drawing.Point(695, 123); this.checkBox1.Name = "checkBox1"; this.checkBox1.Size = new System.Drawing.Size(116, 17); this.checkBox1.TabIndex = 7; this.checkBox1.Text = "Unterverzeichnisse"; this.checkBox1.UseVisualStyleBackColor = true; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(920, 617); this.Controls.Add(this.checkBox1); this.Controls.Add(this.label2); this.Controls.Add(this.textBox1); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.label1); this.Controls.Add(this.button1); this.Controls.Add(this.listBox1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D; this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.ListBox listBox1; private System.Windows.Forms.Button button1; private System.Windows.Forms.Label label1; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button3; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Label label2; private System.Windows.Forms.CheckBox checkBox1; } }
######################
CodeBlock3, Programm.cs
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace DeleteFilesByExtension { static class Program { /// <summary> /// Der Haupteinstiegspunkt für die Anwendung. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }
Viele Grüße,
Thorsten
- Als Antwort markiert Thorsten DörflerEditor Sonntag, 25. Juli 2010 16:45
-
Hallo nochmals,
ich sehe gerade, dass Du in einem früheren Beitrag das Löschen mit Nachfrage implementiert hast, daher folgender Änderungsvorschlag für button3_Click in Form1.cs:
private void button3_Click(object sender, EventArgs e) { if (this._fList != null) { foreach (FileInfo FI in _fList) { try { this.listBox1.SelectedItem = FI.FullName; } catch { } //Fragt bei *jeder* Datei nach if (MessageBox.Show("Wollen Sie die Datei \"" + FI.Name + "\" wirklich unwiderruflich löschen?", "Löschen von Dateien", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes) { try { //Kommentarzeichen entfernen, dann wird *wirklich* gelöscht //FI.Delete(); try { this.listBox1.Items.RemoveAt(this.listBox1.SelectedIndex); //Application.DoEvents(); } catch { } } catch { } } } //this.listBox1.Items.Clear(); this.button3.Enabled = false; } }
Viele Grüße,Thorsten
-
Hallo,
Ja der ; war das Problem bei Elmar,
Bei Thorsten habe ich die Split Geschichte von Elmar implementiert.
Es gehen jetzt alle 3 Varianten.
StringBuilder builder = new StringBuilder(0x80);
StringBuilder builderNotDeleted = new StringBuilder(0x80);
@Elmar,
0x80 heißt einfach, es könnten nur 128 geschrieben werden, oder?
Ist das überhaupt notwendig.
Wenn jemand Ideen hat, in den Papierkorb zu löschen, gerne.
Optimal wäre evtl. eine Listbox mit Icons.
Alle Dateien auflisten.
Dann löschen, hierbei wird ein anderes Icon angezeigt.
Weiß nicht, ob das schwierig ist.
http://www.materialordner.de/qrOEbyI96wP6PMZor9BtjvbxhieAI5R.html
@Thorsten,
Danke für das obige Beispiel. Werde es im Detail morgen prüfen.
Grüße Andreas
~~~~~~~~
private void btnDeleteCompilerFiles_Click(object sender, EventArgs e)
{
bool doSubDirectories = true;
DirectoryInfo dir = new DirectoryInfo(@"c:\_Prog\CSharp\Test\Regression\");
List<FileInfo> fList = new List<FileInfo>();
//string[] Extensions = new string[] { "*.ncb, *.obj,*.sbr,*.bsc,*.pdb,*.ilk,*.idb,*.tlh,*.tli" };
string[] Extensions = new string[128];// { "*.ncb; *.obj; *.sbr; *.bsc; *.pdb; *.ilk; *.idb; *.tlh; *.tli" };
string searchPatterns = "*.ncb; *.obj; *.sbr; *.bsc; *.pdb; *.ilk; *.idb; *.tlh; *.tli";
int i = 0;
foreach (string searchExtensions in searchPatterns.Split(';'))
{
var pattern = searchExtensions.Trim();
if (pattern.Length > 0)
{
Extensions[i] = pattern;
i++;
}
}
-
Hallo Andreas,
bezüglich: 0x80 heißt einfach, es könnten nur 128 geschrieben werden, oder?
Ja, es ist eine hexadezimale Konstante. Und es wäre hier (das nur Testcode) nicht notwendig.
Durch die Vorgabe der Kapazität eines StringBuilders hat man ein weniger Pufferallokationen,
wenn man bereits eine größere Länge erwartet, was dem Garbage Collector weniger Arbeit macht.
Relevant das hier letztendlich nicht.Und es ist wie gesagt nur Beispielcode um den Einsatz der Methode zu zeigen.
Bezüglich des Löschen in den Papierkorb:
Wenn Du die Liste weiter bearbeiten möchtest, so könntest Du die gelieferte Liste
zum Beispiel an eine CheckedListBox übergeben.
(Wenn Du damit Probleme hast, oder einen anderen Weg gehen möchtest,
mache bitte einen neuen Thread auf, dieser hier wird langsam unübersichtlich ;-)
Ich habe hier zwar mittlerweile grundsätzlich funktionierenden Code.
Durch die etwas krude Implementation (wie bei der Shell nicht ganz unüblich ;-)
würde der wesentlich mehr Tests erfordern, um für mich als "produktiv" gelten
zu können - und die Zeit habe ich derzeit nicht.
Ich würde Dir empfehlen - wie auch im Pinvoke Link erwähnt,
auf die bei Visual Basic schon vorhandene Funktionalität zurückzugreifen.Dazu mußt Du die Microsoft.VisualBasic.dll in die Projekt Referenzen aufnehmen.
Dann im Kopf einfügenusing Microsoft.VisualBasic.FileIO;
und anstatt eines File.Delete:
FileSystem.DeleteFile(filename, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
Für mehr siehe FileSystem.DeleteFile
Und wäre eine der wenigen Stellen, wo die Visual Basic My-Erweiterungen, zu denen es gehört,
dem Rest der BCL ein wenig voraus hat (in die man keine Windows spezifischen Dinge einbauen wollte).Ich hatte Deinen Code zwar nur überflogen (um obiges nachzuvollziehen).
Auffiel die Prüfung via File.Exists vor dem File.Delete . Das ist nicht notwendig,
da File.Delete stillschweigend zurückkehrt, wenn die Datei nicht existiert,
siehe die Dokumentation dazu.Zum Schluß noch einmal die Empfehlung:
Lies (bzw. überflieg) die Dokumentation jeder neuen Klasse und Methode.
Das mag anfangs etwas aufhalten, auf Dauer lernt man aber am schnellsten -
zumindest für mich gilt das.
Auch wenn Du bereits Erfahrung in C(++) hast (hatte ich auch):
.NET ist an vielen Stellen anders konzipiert - im Vergleich zum Windows-API
oder Frameworks wie dem MFC/STL usw. - und gleiche oder ähnliche Klassen-
und/oder Methodennamen arbeiten nicht unbedingt so wie man (anfangs) erwartet.Arbeitet man länger damit, erkennt man (meist) den Sinn dahinter.
So mag File.Delete als typisches Beispiel gelten. Um keine unnötige
Fehlerbehandlung zu erfordern, die den Code nur unübersichtlich gestalten,
wird dort das Fehlen der Datei nicht als Ausnahmebedingung betrachtet.
Und nur Dinge wie ungültige Verzeichnisse (es fehlt mehr als der nur die Datei)
lösen Ausnahmen aus.Gruß Elmar
Zum @Thorsten übergebe ich das Wort an Thorsten ;-)
- Als Antwort markiert Thorsten DörflerEditor Sonntag, 25. Juli 2010 16:46
-
Zum @Thorsten übergebe ich das Wort an Thorsten ;-)
... ja, vielen Dank Elmar! :-)Ich habe aber heute nichts mehr zu melden, bin voll mit meinen Bild-Verzerr-Dingen beschäftigt. Bild:
http://cid-d5e5bd21dbf5e4e9.photos.live.com/self.aspx/%c3%96ffentlich/Aufrollen^_verschieben^_2.jpg
Die Idee mit der CheckedListBox finde ich sehr gut, da könnte der Benutzer auf einfache Weise auswählen, welche Dateien gelöscht werden sollten.
Viele Grüße,
Thorsten
-
Hallo Zusammen,
>Und es ist wie gesagt nur Beispielcode um den Einsatz der Methode zu zeigen.
>Wenn Du die Liste weiter bearbeiten möchtest, so könntest Du die gelieferte Liste
>zum Beispiel an eine CheckedListBox übergeben.
>(Wenn Du damit Probleme hast, oder einen anderen Weg gehen möchtest,
>mache bitte einen neuen Thread auf, dieser hier wird langsam unübersichtlich ;-)
>
>Ich würde Dir empfehlen - wie auch im Pinvoke Link erwähnt,
>auf die bei Visual Basic schon vorhandene Funktionalität zurückzugreifen.
>
>Dazu mußt Du die Microsoft.VisualBasic.dll in die Projekt Referenzen aufnehmen.
>Dann im Kopf einfügen
>
//und anstatt eines File.Delete:
> FileSystem.DeleteFile(FI.FullName,
> UIOption.OnlyErrorDialogs,
> RecycleOption.SendToRecycleBin);tadellos und passt.
Bild1
http://www1.minpic.de/bild_anzeigen.php?id=118184&key=77730356&endeBild2
http://www1.minpic.de/bild_anzeigen.php?id=118185&key=86036511&endeProjekt
http://www.materialordner.de/8HDZ7xQk4QrUjyIH0krsKh6lgW9cyIEv.html
Superanleitung.Grüße Andreas
-
Hallo Andreas,
ich möchte Dich mal darauf hinweisen, Deine Postings auch (wenn Du es so siehst) irgendwann mit "als Antwort kennzeichnen" zu markieren. Man kann auch mal zwischendurch schon einen Hinweis "als hilfreich" einstufen. Gehe ggf. mal auch andere Threads durch und schaue, ob Du da was vergessen hast ;-)
Ich finde Thorsten und Elmar haben hier ganz schön Zeit investiert.
ciao Frank- Als Antwort markiert Andreas Bauer2 Sonntag, 25. Juli 2010 16:21
- Tag als Antwort aufgehoben Thorsten DörflerEditor Sonntag, 25. Juli 2010 16:35
-
Hallo Andreas,
ich möchte Dich mal darauf hinweisen, Deine Postings auch (wenn Du es so siehst) irgendwann mit "als Antwort kennzeichnen" zu markieren. Man kann auch mal zwischendurch schon einen Hinweis "als hilfreich" einstufen. Gehe ggf. mal auch andere Threads durch und schaue, ob Du da was vergessen hast ;-)
Ich finde Thorsten und Elmar haben hier ganz schön Zeit investiert.
ciao Frank
>tadellos und passt.Hallo Frank,
ich habe mich bedankt und der Thread ist abgeschlossen.
Wo ist das Problem?
Vielleicht darin, dass die Art des Forum nicht übersichtlich ist.
Es fehlt die Baumstruktur. Wenn es mehrere so sehen, wird Microsoft etwas ändern, oder?
http://www1.minpic.de/bild_anzeigen.php?id=118365&key=22749412&ende
Andreas
- Als Antwort markiert Andreas Bauer2 Sonntag, 25. Juli 2010 16:35
- Tag als Antwort aufgehoben Thorsten DörflerEditor Sonntag, 25. Juli 2010 16:41
-
Hallo Andreas,
ich habe mich bedankt und der Thread ist abgeschlossen.
Wo ist das Problem?
normalerweise schließt man einen Thread dadurch ab, dass man die Beiträge als Antwort markiert, die einem zur Lösung des Problems geholfen haben. Daher habe ich Deine Markierungen auch aufgehoben, da diese sicher nicht die Lösung Deines Problems darstellen. Durch das Markieren als Antwort honorierst Du nicht nur die Leistung der Beantworter, sondern hilfst auch anderen, mit einem ähnlichen Problem sich eben nicht durch viele Beiträge lesen zu müssen, um die Antwort zu finden.
Vielleicht darin, dass die Art des Forum nicht übersichtlich ist.
Nein, daran liegt das sicher nicht.
Es fehlt die Baumstruktur.
Schau mal rechts unter "Meine Einstellungen", dort kannst Du die Darstellung der Forenbeiträge ändern. Wobei diese Ansicht bei einem so tief verschachtelten Thread auch nicht optimal ist.
Thorsten Dörfler
Microsoft MVP Visual Basic
vb-faq.de -
Hallo Andreas,
gut - lieb von Dir, dass Du mein Posting als Antwort markiert hattest, aber so hatte ich das nicht gemeint ;-)
Ich meine: Du solltest eben das für Dich fachlich zielführende/geeignetste Posting als Antwort markieren. Das kann hier nur ein Posting von Elmar oder Thorsten Gudera sein, die Dir IMHO am meisten geholfen haben. Daran sehen viele auch, dass sich die Frage geklärt hat. Man kann trotzdem später noch posten und eventuell eine bessere fachlichen Hinweis geben, der ggf. auch dann als Antwort markiert wird.
Weisst Du - für andere erspart das später Arbeit, wenn sie gleich oben die dem OP nach geeignetste Lösung finden.
Auch kannst Du ja Hilfreich - Punkte vergeben. Auch daran kann man sich orientieren.> Threadansicht
die gibt es ja schon unter "Meine Einstellungen" ganz rechts oben.
ciao Frank -
Hallo Andreas,
Danke ja schon richtig erkannt, sieht besser aus .
string searchPattern = "*.ncb" ;
// | *.obj"; //,*.obj,*.sbr,*.bsc,*.pdb,*.ilk,*.idb,*.tlh,*.tli";
//string[] s1 = dir.GetFiles("*.ncb");Was nicht funktionierte ist, wenn ich mehrere unterschiedliche extension habe.
Ein RegExp searchPattern mit mehreren Extension sähe etwa so aus:
string searchPattern = @"^.+\.(ncb|obj|sbr|bsc|pdb|ilk|idb|tlh|tli)$" ;
wenn du gegen Datei-Name bzw. -Pfad testest.
Die ganze Suche liesse sich knapper gestalten, wenn z.B. GetFiles mit rekursiver Option (SearchOption.AllDirectories) verwendet wird.
Beim Packen und Sortieren wäre Linq ganz nützlich, um unnötigen Enumerierungs-Code zu vermeiden und auch ums übersichtlich zu halten:public static string[] SearchPathesFlat(string startDir, params string[] extensions) { if (extensions == null || extensions.Length == 0) return new string[0]; StringBuilder regexBuilder = new StringBuilder(@"^.+\.("); regexBuilder.Append(string.Join("|", extensions)); regexBuilder.Append(")$"); Regex regexExtensions = new Regex(regexBuilder.ToString(), RegexOptions.IgnoreCase | RegexOptions.Compiled); string[] result = Directory.GetFiles(startDir, "*.*", SearchOption.AllDirectories) //rekurisv ALLE Dateien holen .Select(fi => regexExtensions.Match(fi)) //Regex-Match-Objekt zwischen speichern .Where(ma => ma.Success) //Nur Treffer filtern, nit richtiger Extension .OrderBy(ma => ma.Groups[1].Value, StringComparer.CurrentCultureIgnoreCase) //Sortieren nach Extension .ThenBy(ma => ma.Groups[0].Value, StringComparer.CurrentCultureIgnoreCase); //Dann Sortieren nach Pfad .Select(ma => ma.Groups[0].Value) //nur Pfad projizieren .ToArray(); return result; }
Aufruf wäre dann:
string[] delFiles = SearchPathesFlat(@"C:\Projekte\VC\P1", "obj", "sbr", "bsc", "pdb", "ilk", "idb", "tlh", "tli"); File.WriteAllLines(@"C:\Projekte\VC\P1\del.log", delFiles);
-
string[] delFiles = SearchPathesFlat(@"C:\Projekte\VC\P1", "obj", "sbr", "bsc", "pdb", "ilk", "idb", "tlh", "tli"); File.WriteAllLines(@"C:\Projekte\VC\P1\del.log", delFiles);
Hallo,
using System.Text.RegularExpressions; using System.IO; private void btnFilesDelete_Click(object sender, EventArgs e) { // string searchPattern = @"^.+\.(ncb|obj|sbr|bsc|pdb|ilk|idb|tlh|tli)$" ; string[] delFiles = SearchPathesFlat( @"C:\_Test\f1", "obj", "sbr", "bsc", "pdb", "ilk", "idb", "tlh", "tli"); File.WriteAllLines(@"C:\_Test\f1\del.log", delFiles); #### } public static string[] SearchPathesFlat(string startDir, params string[] extensions) { if (extensions == null || extensions.Length == 0) return new string[0]; StringBuilder regexBuilder = new StringBuilder(@"^.+\.("); regexBuilder.Append(string.Join("|", extensions)); regexBuilder.Append(")$"); Regex regexExtensions = new Regex(regexBuilder.ToString(), RegexOptions.IgnoreCase | RegexOptions.Compiled); string[] result = Directory.GetFiles(startDir, "*.*", SearchOption.AllDirectories) //rekurisv ALLE Dateien holen .Select(fi => regexExtensions.Match(fi)) //Regex-Match-Objekt zwischen speichern .Where(ma => ma.Success) //Nur Treffer filtern, nit richtiger Extension .OrderBy(ma => ma.Groups[1].Value, StringComparer.CurrentCultureIgnoreCase) //Sortieren nach Extension .ThenBy(ma => ma.Groups[0].Value, StringComparer.CurrentCultureIgnoreCase) //Dann Sortieren nach Pfad .Select(ma => ma.Groups[0].Value) //nur Pfad projizieren .ToArray(); return result; }
Die ganze Suche liesse sich knapper gestalten, wenn z.B. GetFiles mit rekursiver Option (SearchOption.AllDirectories) verwendet wird.Beim Packen und Sortieren wäre Linq ganz nützlich, um unnötigen Enumerierungs-Code zu vermeiden und auch ums übersichtlich zu halten:
http://msdn.microsoft.com/de-de/library/wz42302f(v=VS.90).aspxhttp://msdn.microsoft.com/de-de/library/bb546167(VS.90).aspx
Das hast Du ja gemacht,oder?Zum richten löschen müsste ich einfach #### ans dieser Stelle alles nochmals durchlaufen. Sehe ich das richtig?Wie würdest du es final lösen?
Ist ja super kanpp, muss man erst mal drauf kommen. Wäre ich nicht, nie und nimmer.Gewusst wie halt wieder.
- regexBuilder {^.+\.(obj|sbr|bsc|pdb|ilk|idb|tlh|tli} System.Text.StringBuilderKannst du hierzu noch kurz was sagen?^.+\.
Geht das in die Richtung? Evtl. kannst du es noch besser erläutern.http://msdn.microsoft.com/de-de/library/bb546159(v=VS.90).aspx
.Select(fi => regexExtensions.Match(fi)).Where(ma => ma.Success)fi , ma ist mir unklar
Danke für den Supertipp!
Grüße Andreas -
private void btnFilesDelete_Click(object sender, EventArgs e) { // string searchPattern = @"^.+\.(ncb|obj|sbr|bsc|pdb|ilk|idb|tlh|tli)$" ; string[] delFiles = SearchPathesFlat( @"C:\_Test\f1", "obj", "sbr", "bsc", "pdb", "ilk", "idb", "tlh", "tli"); File.WriteAllLines(@"C:\_Test\f1\del.log", delFiles); #### }
> Zum richten löschen müsste ich einfach #### ans dieser Stelle alles nochmals
> durchlaufen. Sehe ich das richtig?
> Wie würdest du es final lösen?Hallo Andreas,Ganz schlicht mit:foreach (string path in delFiles){try{File.Delete(path);}catch (IOException ie){...}catch (UnauthorizedAccessException ue){...}catch (/* andere denkbare Exceptions von File.Delete */){...}}
> Ist ja super kanpp, muss man erst mal drauf kommen. Wäre ich nicht, nie und nimmer.> Gewusst wie halt wieder.
- regexBuilder{^.+\.(obj|sbr|bsc|pdb|ilk|idb|tlh|tli} System.Text.StringBuilderKannst du hierzu noch kurz was sagen?^.+\.^ : markiert im Muster den Beginn des zu prüfenden Strings, '$' würde das Ende markieren.. + : 1 bis unendliche viel beliebige Zeichen, entspricht in etwa '*' im Wildcard-Muster.\. : Ein Punkt als Zeichen. Bezieht sich auf den Punkt als Trennsymbol für die Datei-ExtensionLetzte endlich entspricht es einem fiktiven Wildcard-Muster wie:*.obj|*.sbr|*.bsc|*.pdb|*.ilk|*.idb|*.tlh|*.tlinur das ein Metazeichen wie '|' für ODER-Verknüpfungen in Wildcard-Syntax nicht existiert.StringBuilder ist eine .NET-Klasse um effektiv und v.a. performanteinzelne Textbausteine zusammen zu fügen. Ist deutlich schnelleralsstring all = "Bau" + " " + "mir einen" + " " + "Satz";
> .Select(fi => regexExtensions.Match(fi))> .Where(ma => ma.Success)> fi , ma ist mir unklar.Select(fi => regexExtensions.Match(fi))Hier wird für jeden String/Pfad den GetFiles liefert einRegex.Match-Objekt gebildet (und zwar bezogen auf dasPattern von regexExtensions). Das Match-Objekt wird auch für Dateiengebildet, die dem Muster NICHT entsprechen, bei denen istdie Success-Eigenschaft dann 'false'.Durch den Select erhältst Du im nächsten Schritt also eine
Datenmenge vom Typ IEnumarable<Match>.
Aus diesen filterst Du (mit 'Where') nur diejenigen Matches heraus,
deren Success-Eigenchaft 'true' ist. Das heisst, die dem Regex-Muster
entsprechen. Im Ergebnis diejenigen Dateien, die die gewünschte
Dateiendung aufweisen.'ma' ist innerhalb des Lambda-Ausdruck die Deklaration des einzelnenRegex.Match-Objekts. Die Bezeichnung ist - wie prinzipiell jede
Variablen-Bezeichnung - beliebig.
Man könnte auch 'match' schreiben oder ganz was anderes.Gruß,Christoph