Autor Beitrag
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Mi 22.06.22 14:09 
UserTom hat folgendes geschrieben:
Weißt du, wo ich die Bytes vertauschen müsste, wenn überhaupt?

Das machen wohl die Methoden in der "Sharp7.cs", z.B. für GetIntAt (die du aber nicht nutzt).

Funktioniert denn das Testprogramm bei der realen SPS?

Ansonsten schreibe einfach selber ein Testprogramm (ohne BackgroudnWorker etc), daß einfach nur einen Connect durchführt und danach dann die Daten liest (und messe z.B. mit Stopwatch die Zeiten) - kann ja auch ein einfaches Konsolenprogramm sein.
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Mi 22.06.22 17:25 
Servus,

Zitat:
Funktioniert denn das Testprogramm bei der realen SPS?


Ich habe mit dem echten Programm getestet. Es funktioniert das Ordner erstellen und auch das kopieren.
Die GUI friert nicht ein. Die Progressbar Anzeige passt nicht zu meinem kopieren.
Das kopieren dauert für die Größe der Dateien sehr lange. 29 Dateien und 4 Ordner. 1,18MB.

Die Progressbar Anzeige habe ich wie folgt umgebaut. Das hatte auch Ralf in einem Post so ähnlich dargestellt.

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:
private void BW_CopyAllFiles_DoWork(object sender, DoWorkEventArgs e)
        {
            var bw = sender as BackgroundWorker;

            bw.ReportProgress(0);

            S7VariablenResult s7VariablenResult = ReadResult();

            //Ordner erstellen
            string createTargetPath = Path.Combine(DEFAULTTARGETPATH, s7VariablenResult.FolderName);
            Directory.CreateDirectory(createTargetPath);

            bw.ReportProgress(25);


            for (int i = 0; i < cbActivateLocalApps.Length; i++)
            {
                if (cbActivateLocalApps[i].Checked == true)
                {
                    string praegeCodeNrFolderName = s7VariablenResult.FolderName;
                    string praegeCodeNrFileName = s7VariablenResult.PraegeCodeNr;
                    string sourceFilePath = uivalues.SourceFilePathLocalApps[i];
                    string targetPath = DEFAULTTARGETPATH;

                    MoveFilesfromLocal(praegeCodeNrFolderName, praegeCodeNrFileName, sourceFilePath, targetPath);
                }
            }

            bw.ReportProgress(50);

            for (int j = 0; j < cbActivateLocalApps.Length; j++)
            {
                if (cbActivateLocalApps[j].Checked == true)
                {
                    string praegeCodeNrFolderName = s7VariablenResult.FolderName;
                    string praegeCode2NrFileName = s7VariablenResult.PraegeCode2Nr;
                    string sourceFilePath = uivalues.SourceFilePathLocalApps[j];
                    string targetPath = DEFAULTTARGETPATH;

                    MoveFilesCode2fromLocal(praegeCodeNrFolderName, praegeCode2NrFileName, sourceFilePath, targetPath);
                }
            }

            bw.ReportProgress(75);

            for (int k = 0; k < cbActivateNetApps.Length; k++)
            {
                if (cbActivateNetApps[k].Checked == true)
                {
                    string praegeCodeNrFolderName = s7VariablenResult.FolderName;
                    string praegeCodeNrFileName = s7VariablenResult.PraegeCodeNr;
                    string sourceFilePath = uivalues.SourceFilePathNetApps[k];
                    string targetPath = DEFAULTTARGETPATH;

                    CopyFilesfromNetwork(praegeCodeNrFolderName, praegeCodeNrFileName, sourceFilePath, targetPath);
                }
            }

            //Report 100% completion on operation completed
            bw.ReportProgress(100);
        }


So sieht die Prozessbar Anzeige besser aus und passt zum Ablauf. Bei 75% stockt es, weil da die Dateien vom Netzwerk kopiert werden.
Und das wundert mich, weil auf 3 von den 5 PCs nur jeweils eine 2kB csv-Datei liegt, auf dem 4. PC liegen 2 Dateien zusammen mit 300kB und auf dem 5. PC liegt ein Ordner mit 3 Dateien mit 647kB.
Ich vermute das die Rechte nicht so schnell freigegeben werden. Sie sind da und sie werden kopiert.
Firewall ist überall ausgeschaltet. Es sind autarke Anlagen die keine Verbindung nach draußen haben.
Mal eine Frage, ich habe nicht den gleichen Benutzer auf den PCs angelegt wie auf dem Quell-PC.
Das sind Applikations-PCs und die haben Ihre Benutzer die von den Firmen eingerichtet wurden.
Würde das was bringen, wenn auf den PCs der gleiche Benutzer wäre? Es sind alles Windows 10 PCs.
Ich kann bei den Firmen anfragen, ob ich das ändern darf. Es könnte sich auf die Applikationssoftware auswirken.

So ich werde weiter an dem DB arbeiten.

ausblenden C#-Quelltext
1:
 s7VariablenResult.PraegeCodeNr = S7.GetStringAt(dbbuffer, uivalues.PraegeCodeDBPos);					


S7.GetStringAt möchte ich austauschen gegen Char wie nach der Vorlage

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
private ComponentResult LeakResult()

{    ComponentResult Result = new ComponentResult();

    byte[] Buffer = new byte[26];

    // Reads the buffer.

    Client.DBRead(100026, Buffer);

    // Extracts the fields and inserts them into the struct

    Result.SerialNumber = S7.GetCharsAt(Buffer, 012);


Alles was nicht gebraucht wird muss raus.

Also vielen Dank nochmal für deine Antwort und Hilfe.

Grüße Tom
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4643
Erhaltene Danke: 967


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 22.06.22 19:21 
Zitat:
Mal eine Frage, ich habe nicht den gleichen Benutzer auf den PCs angelegt wie auf dem Quell-PC.
Das sind Applikations-PCs und die haben Ihre Benutzer die von den Firmen eingerichtet wurden.
Würde das was bringen, wenn auf den PCs der gleiche Benutzer wäre?

Eher nein. Aber mußt du dich den im Moment irgendwo in deinem Programm für die Freigabe authentifizieren?

Zitat:
S7.GetStringAt möchte ich austauschen gegen Char wie nach der Vorlage

Ob char oder string glaube ich auch nicht das das einen Unterschied macht. Das lesen der Daten von der Quelle macht doch DBRead oder? Der potentiel teure IO Zugriff passiert also schon da.
Die S7 Klasse holt nur aus dem Byte Array die passenden Bytes und macht einen anderen Datentyp draus aus (Hier String oder Char Array)?

Was genau Zeit kostet solltest du aber messen und nicht raten.
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Do 23.06.22 07:22 
Hallo Ralf,

Vielen Dank für deine Antwort.

Zitat:
Aber mußt du dich den im Moment irgendwo in deinem Programm für die Freigabe authentifizieren?

Das nicht, aber dann ist es noch unverständlicher, warum das Programm dafür so lange braucht.
Ich habe das Programm mal die Nachtschicht laufen lassen. Es hat nur jedes 2. Bauteil geschafft, die Daten zu kopieren.
Das Programm bleibt an dieser Stelle für 40sek. hängen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
bw.ReportProgress(75);

            for (int k = 0; k < cbActivateNetApps.Length; k++)
            {
                if (cbActivateNetApps[k].Checked == true)
                {
                    string praegeCodeNrFolderName = s7VariablenResult.FolderName;
                    string praegeCodeNrFileName = s7VariablenResult.PraegeCodeNr;
                    string sourceFilePath = uivalues.SourceFilePathNetApps[k];
                    string targetPath = DEFAULTTARGETPATH;

                    CopyFilesfromNetwork(praegeCodeNrFolderName, praegeCodeNrFileName, sourceFilePath, targetPath);
                }
            }


Das ist natürlich viel zu lang. Die Frage ist, warum er da hängen bleibt.
Vorher haben wir das von der Visualisierung Zenon (Copa Data) in der Runtime mit VBA erledigen lassen.
Alle Dateien wurden in max. 8 sek. kopiert. Der Nachteil war, dass die Runtime dann für diese Zeit blockiert war.
Wenn man in diesem Moment eine Störung hat, dann zählt jede Sekunde. Taktzeit bestimmt die Anzahl der produzierten Teile.

Das neue Tool sollte dieses Handicap mit der Runtime beheben. Das war halt eine Empfehlung von der Firma Copa Data.

Gibt es einen großen Unterschied zwischen C#:
ausblenden C#-Quelltext
1:
using Microsoft.VisualBasic.FileIO;					


und VBA 7.1:

ausblenden Quelltext
1:
2:
'Windows Dateioperationen zur Verfügung stellen
Set oFSO = CreateObject("Scripting.FileSystemObject") '


Ich bin sehr enttäuscht, dass meine ganze investierte Zeit wahrscheinlich für die Katz war.
Ich greife natürlich nach jedem Strohhalm.
Gibt es bei C# Befehle zum Kopieren oder verschieben, die nicht auf VisualBasic beruhen?
Wenn, der alte VBA Code das in kurzer Zeit schafft, dann müsste doch das neue Tool, das doch auch schaffen können.
Die Quellen und die Ziele sind in beiden Programmierungen gleich.

Habt ihr vielleicht noch eine Idee, wie das Verbessern könnte?

Grüße Tom
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Do 23.06.22 09:17 
Hallo,

bei dir lokal läuft das doch schnell genug, d.h. es wird an der Umgebung auf dem Produktionsrechner liegen.
Sowohl die VB-Dateioperationen in Microsoft.VisualBasic.FileIO.FileSystem als auch die in der Klasse System.IO.File beruhen alle auf den WinAPI-Dateiverwaltungsfunktionen (die auch sonst von allen Windows-Programmen, wie z.B. Windows Explorer intern benutzt werden).

Es gibt ja in deinem Programm eine Unterscheidung zwischen "Local" und "Net" - worauf bezieht sich das genau?
Und wenn du manuell (oder per Batch-Script o.ä.) diese Dateien kopierst, ist das dann schnell genug?

Hast du auch schon mal in den Task-Manager (bzw. den Ressourcenmonitor) geschaut, wie hoch die generelle Auslastung auf dem Rechner ist?

Frühzeitige (bzw. regelmäßige) Integrationstests sowie Ausführung auf dem Zielsystem sind ein wesentlicher Bestandteil moderner (agiler) Entwicklung.
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Do 23.06.22 17:52 
Hallo Th69,

Zitat:
bei dir lokal läuft das doch schnell genug, d.h. es wird an der Umgebung auf dem Produktionsrechner liegen.
Ja genau und ich denke ich habe da was gefunden. Zum Beispiel bei dem PC wo das Programm bei 75% stehen bleibt und es so lange dauert da habe ich mich gefragt warum. Ich habe mir dann mal den PC genauer angeschaut und in dem Quellordner fast 30000 Ordner gefunden. Ich habe dann mal unsere IT gefragt ob es möglich ist das das Programm deswegen so lange braucht. Die meinten ja, weil es so viele Ordner prüfen muss bis es den richtigen Ordner gefunden hat.

Zitat:
Es gibt ja in deinem Programm eine Unterscheidung zwischen "Local" und "Net" - worauf bezieht sich das genau?
Es gibt ein TabControl wo die ganzen Quelle Pfade eingetragen werden.

Eine TabPage ist für Lokale Pfade:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
        private void ChooseSourcePathLocalApp_Click(object sender, EventArgs e)
        {
            if (sender is TextBox textBox)
            {
                if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
                {
                    textBox.Text = folderBrowserDialog1.SelectedPath;
                }
            }
        }


die andere TabPage für UNC Pfade:
ausblenden 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:
 
        private void ChooseSourcePathNetApp_Click(object sender, EventArgs e)
        {
            if (sender is TextBox textBox)
            {
                textBox.Text = GetNetworkFolders(new FolderBrowserDialog());
            }
        }

        private string GetNetworkFolders(FolderBrowserDialog oFolderBrowserDialog)
        {
            Type type = oFolderBrowserDialog.GetType();
            FieldInfo fieldInfo = type.GetField("rootFolder", BindingFlags.NonPublic | BindingFlags.Instance);
            fieldInfo.SetValue(oFolderBrowserDialog, 18);
            if (oFolderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                return oFolderBrowserDialog.SelectedPath.ToString();
            }
            else
            {
                return "";
            }
        }

Das Auswählen mache ich über FolderBrowserDialog. Wenn man nach UNC Pfade schaut dann dauert es ein bisschen aber ne praktische Sache.

Zitat:
Hast du auch schon mal in den Task-Manager

Bis jetzt noch nicht da ich heute mich um andere Dinge kümmern musste.
Aber das werde ich dann mal machen und gleichzeitig werde ich mal testen wie es sich verhält wenn im Quellordner nur die Datei vorhanden ist die aktuell benötigt wird.

So vielen Dank für deine Unterstützung.

Grüße Tom

Moderiert von user profile iconTh69: Beitragsformatierung überarbeitet.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Fr 24.06.22 09:21 
30000 Unterordner - das ist ja genauso schlimm wie bei meinem ehemaligen Projekt die ca. 30000 Code-Zeilen!

Wie kannst du denn da über den FolderBrowserDialog den passenden Ordner vernünftig auswählen?

Ich hatte auch deswegen nach "Local" und "Net" gefragt, ob der Zugriff darauf einen Unterschied macht, aber so wie ich deinen Beitrag verstehe ist es schon bei "Local", eben wegen der vielen Unterordner, langsam.

Benötigst du denn nur Zugriff auf einige wenige dieser Unterordner? Dann könntest du evtl. einen eigenen Laufwerksbuchstaben dafür anlegen und darüber dann zugreifen, s.a. Windows 10: Lokale Ordner als Laufwerk in Windows einbinden (s. Bilder-Galerie).
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Fr 24.06.22 12:38 
Hallo Th69,


Vielen Dank für deine Antwort. Das hast du jetzt leider falsch verstanden.
Im Anhang siehst du ein Screenshot vom Dialog wo die Quellpfade ausgewählt werden.
Zum Beispiel \\computer\PDE\kle15r02\AppData. In dem AppData Ordner sind die 30000 Unterordner.
Ich brauche keinen Unterordner auswählen.

Der Programmcode für "CopyDirectory" sucht die 30000 Unterordner nach dem richtigen Ordnernamen ab der kopiert werden soll.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public static void CopyDirectoryfromNetwork(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> dirs = Directory.EnumerateDirectories(sourceFilePath, "*", System.IO.SearchOption.AllDirectories).Where(x => x.Contains(praegeCodeNrFileName));

            foreach (string dir in dirs)
            {
                TryAction(() => FileSystem.CopyDirectory(dir, dir.Replace(sourceFilePath, Path.Combine(targetPath, praegeCodeNrFolderName)), true));
                TryAction(() => FileSystem.DeleteDirectory(dir, DeleteDirectoryOption.DeleteAllContents));
            }
        }


Und das dauert so lange oder? Mein Fehler ist das da so viele Unterordner drin sind.

Ich hatte ja erzählt das die Visu Zenon mit VBA das kopieren macht.
Im VBA Code gibt es aber keine lösch befehle. So summieren sich die Ordner und Dateien.
Daran habe ich nicht mehr gedacht. Und in meinem Programm sind Lösch Befehle mit drin.
Aber weil die GUI blockierte ist mein Programm bis heute noch nicht zum Einsatz gekommen.
Mit Eurer Hilfe ist der Backgroundworker reingekommen und jetzt sieht es besser aus.

Bei dem ersten Test hat es nicht so gut funktioniert, weil alle Quell-Ordner auf den 5 PCs
voll sind mit Unterordner oder Dateien. Ich habe zum Beispiel auf den einem PC über 200000
Dateien gefunden. Das Programm brauch eine "Ewigkeit" bis es die richtige Datei gefunden hat.

Oder siehst du das anders?

Noch eine andere Frage.

Mit dem folgenden Code über FolderBrowsingdialog wähle ich die Netzwerkordner aus.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
private void ChooseSourcePathNetApp_Click(object sender, EventArgs e)
        {
            if (sender is TextBox textBox)
            {
                textBox.Text = GetNetworkFolders(new FolderBrowserDialog());
            }
        }

        private string GetNetworkFolders(FolderBrowserDialog oFolderBrowserDialog)
        {
            Type type = oFolderBrowserDialog.GetType();
            FieldInfo fieldInfo = type.GetField("rootFolder", BindingFlags.NonPublic | BindingFlags.Instance);
            fieldInfo.SetValue(oFolderBrowserDialog, 18);
            if (oFolderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                return oFolderBrowserDialog.SelectedPath.ToString();
            }
            else
            {
                return "";
            }
        }


Der Dialog brauch recht lange das Netzwerk einzulesen ca.30 sek.
Gibt es eine bessere Variante?


Vielen Dank für deine Ideen.

Grüße Tom
Einloggen, um Attachments anzusehen!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Fr 24.06.22 13:29 
Das ist ja noch schlimmer!

Bedenke mal deinen Code dafür:
ausblenden C#-Quelltext
1:
Directory.EnumerateDirectories(sourceFilePath, "*", System.IO.SearchOption.AllDirectories)					

Damit werden alle Unterordner (+ Unter-Unterordner etc.) durchlaufen - und du wunderst dich, daß das lange dauert?

Benötigst du wirklich SearchOption.AllDirectories (s.a. Anmerkungen dazu im Snippet-Link unten)?

Und wäre ein searchPattern wie
ausblenden C#-Quelltext
1:
"*" + praegeCodeNrFileName + "*"					

nicht viel eleganter (anstatt für jeden Eintrag Where(x => x.Contains(praegeCodeNrFileName) aufzurufen)?!!!

Und kannst du die Datei- und Ordnernamen nicht noch weiter einschränken, d.h. kann der praegeCodeNrFileName irgendwo im Dateinamen auftauchen oder evtl. nur am Anfang?

PS: Warum überhaupt praegeCodeNrFileName für die Suche nach Ordnern? Du hast doch bei den Kopiermethoden auch noch praegeCodeNrFolderName als Parameter?
Bis jetzt hatte ich mir die Logik deiner Kopiermethoden nicht näher angeschaut gehabt, aber mir kommt es jetzt so vor, als hättest du einfach ein bißchen zu viel Copy&Paste da betrieben, anstatt genau zu überlegen.
Wußtest du denn nicht von Anfang an, daß dort soviele Unterordner vorhanden sind? Das vorherige Programm mußte doch ebenso damit umgehen.

Kannst du auch mal ein paar Beispiele für praegeCodeNrFolderName und praegeCodeNrFileName nennen?

Edit:
Ich habe mir jetzt noch mal deine Methoden MoveFilesfromLocal sowie CopyFilesfromNetwork angesehen.
Kann es sein, daß im Fall Local/NetSubFolderUses[i].Checked zwar alle Unterordner durchsucht werden sollen, aber nur vom praegeCodeNrFolderName (und nicht über alle sourceFilePath)?! Oder ist das nur der Name des Zielordners?

PPS: Hier noch Link, um die Dateisuche selber (d.h. mit eigenen Anforderungen daran) zu implementieren: [Snippet] Verzeichnisse und Dateien rekursiv durchlaufen
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Fr 24.06.22 18:29 
Hallo Th69,

Das hat sehr lange gedauert bis ich mir das zusammen gebastelt hatte das alles so kopiert wird wie ich es benötige. Wenn das natürlich schlecht ist und deswegen alles so lange dauert wäre ich dir sehr dankbar wenn du mir helfen könntest das zu verbessern.

Zitat:
Benötigst du wirklich SearchOption.AllDirectories

Wahrscheinlich nicht aber so funktioniert es.

Also Zielpfad weißt du ja schon. D:\S7_Export\AppData\ + der Ordner der jedesmal erstellt wird.
So ein Ordnername sieht wie folgt aus: 22062415443R oder L

Jahr 22 / Monat 06 / Tag 24 / St. 15 / Min. 47 / Sek. 3 (nur die 1. Stelle) / Buchstabe L oder R

ausblenden C#-Quelltext
1:
2:
3:
//Ordner erstellen
string createTargetPath = Path.Combine(DEFAULTTARGETPATH, s7VariablenResult.FolderName);
Directory.CreateDirectory(createTargetPath);

praegeCodeNrFileName -> 22062415473
praegeCodeNrFolderName -> 22062415473R oder L
praegeCode2NrFileName -> 22062414432 (separates Bauteil was vorher produziert wird)

Diese Werte werden von der SPS vorgegeben, da habe ich keinen Einfluss drauf.

So der
1. Lokale Sourcepath ist D:\S7_Export\Bosch - Die Datei sieht so aus: Ch_22062415473.txt

2. D:\S7_Export\Sensopart\x015id02xa1
Die möglichen Dateien:
22062415473_x015id02xa1_Job1_Pass.jpg (bis Job6)
oder
22062415473_x015id02xa1_Job1_Fail.jpg (bis Job6)
Pass und Fail können beide zusammen auftauchen. Es sollte natürlich nur Pass sein.

3. D:\S7_Export\Sensopart\x020id01xa1
22062414432_x020id02xa1_Job1_Pass.jpg (bis Job3) und das gleiche mit Fail.
Die werden hiermit verschoben "public static void MoveFilesCode2fromLocal()" Wegen 2. Code Nr. 22062414432

4. D:\S7_Export\Sensopart\x060id02xa1
22062415473_x060id02xa1_Job1_Pass.jpg
22062415473_x060id02xa1_Job3_Pass.jpg
22062415473_x060id02xa1_Job5_Pass.jpg
oder
22062415473_x060id02xa1_Job2_Pass.jpg
22062415473_x060id02xa1_Job4_Pass.jpg
22062415473_x060id02xa1_Job6_Pass.jpg und / oder das gleiche mit Fail.

5. D:\S7_Export\Tox - TOX_015R01_22062415473_20220624_154734 <-- Ordnerbezeichnung
Hier wird der Ordner kopiert mit Unterordner.
Wahrscheinlich wegen dieser Ordnerbezeichnung habe ich nicht mit * gearbeitet.

ausblenden C#-Quelltext
1:
x.Contains(praegeCodeNrFileName)					

Ist doch praktisch. Aber wahrscheinlich schlecht bedacht.

So nun die Netzwerkpfade.

1. \\tox10r01\AppData - Die Datei 22062415473_10r01_s_2022_06_24.csv
2. \\tox15r01\AppData - Die Datei 22062415473_15r01_s_2022_06_24.csv
3. \\tox15r02\AppData - Die Datei 22062415473_15r02_s_2022_06_24.csv
4. \\kle15r02\AppData - Der Ordner 22062415473 wird kopiert.
5. \\XPegasus\AppData - 2 Dateien 22062415473_HWH.xarch und 22062415473_SB_HWH.xarch

Auf dem Screenshot Gespeichert.jpg siehst du den Ordner 22050500000R mit seinem Inhalt.
Auf dem Screenshot Tabpage_Lokal ist ein Beispiel von der Konfiguration, was alles angeklickt werden muss.
Z.B. SubFolder wenn man einen Ordner kopieren oder verschieben muss.
Activate 2nd Code wenn es Dateien gibt mit einer anderen Prägung.

Zitat:
Und wäre ein searchPattern wie

Ich habe mit Wildcards probiert, aber wie du an Hand der Dateien und Ordnerbezeichnungen siehst und an meinem Code habe ich das nicht hinbekommen.

Zitat:
PS: Warum überhaupt praegeCodeNrFileName für die Suche nach Ordnern? Du hast doch bei den Kopiermethoden auch noch praegeCodeNrFolderName als Parameter?

praegeCodeNrFolderName ist nur zum erstellen des Ordner im ZielPfad. Buchstabe R oder L.
praegeCodeNrFileName ist zum suchen und kopieren der Ordner und Dateien in den Quellpfaden.

Zitat:
Wußtest du denn nicht von Anfang an, daß dort soviele Unterordner vorhanden sind?

Normalerweise sollte sich pro zyklus nur eine Datei oder Ordner in den Quellen befinden.
Wie ich schon mal sagte das Programm (VBA) auf der Visu Zenon löscht die Dateien nicht.
Über die letzten Wochen oder Monate haben sich so viele alte Daten gesammelt woran ich nicht mehr gedacht habe.
Das neue Programm löscht ja auch gleich das kopierte.

Zitat:
Das vorherige Programm mußte doch ebenso damit umgehen.

Mittlerweile hat sich herausgestellt das auch das alte Programm länger braucht.
Aber die Schnittstelle zwischen der SPS und der Visu Zenon ist natürlich eine professionelle Schnittstelle. (Siemens) Da hat man natürlich keinen Verlust bei der Abfrage der Variablen. Das ist halt Echtzeit.

Zitat:
Kann es sein, daß im Fall Local/NetSubFolderUses[i].Checked

Wie du auf dem Bild Tabpage_Lokal gesehen hast ist da ja eine Checkbox. Die muss angeklickt werden wenn ein Ordner kopiert werden muss.
Es gibt Applikationen die erstellen Ordner mit den Dateien. Andere Applikationen erstellen nur Dateien. Am besten siehst du das auf dem Bild Gespeichert.jpg.

Vielen Dank für deine Hilfe.

Grüße Tom

Moderiert von user profile iconTh69: Beitragsformatierung überarbeitet.
Einloggen, um Attachments anzusehen!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Fr 24.06.22 20:16 
OK, das mit den Ordner- und Dateinamen habe ich jetzt wohl verstanden.

Bitte probiere mal direkt als searchPattern: "*" + praegeCodeNrFileName + "*" (damit schon das Dateisystem die Filterung durchführt und nicht alle 30.000 Ordner in deinem Code durchlaufen werden - ist analog wie beim Datenbankzugriff). Dies ist logisch äquivalent zu deinem bisherigen Code, nur eben viel performanter.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4643
Erhaltene Danke: 967


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Fr 24.06.22 20:28 
Zitat:
Directory.EnumerateDirectories(sourceFilePath, "*", System.IO.SearchOption.AllDirectories)

Die Frage war auch ob es AllDirectories sein muss und nicht TopDirectoryOnly reicht. Liegen deine, wie von dir erklärt formatierten, Verzeichnisse nicht direkt in sourceFilePath?
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Fr 24.06.22 22:45 
Hallo,

Vielen Dank für Eure Antworten.

Zitat:
Bitte probiere mal direkt als searchPattern: "*" + praegeCodeNrFileName + "*"


Das habe ich. Ich konnte es in der ganzen Klasse IOFileOperations einbauen.

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:
namespace PDE
{
    internal static class IOFileOperations
    {
        public static void TryAction(Action action)
        {
            try
            {
                action();
            }
            catch (DirectoryNotFoundException ex)
            {
                ex.SaveErrorMessage();
            }
        }

        public static void MoveDirectoryfromLocal(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {            
            IEnumerable<string> dirs = Directory.EnumerateDirectories(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string dir in dirs)
            {
                TryAction(() => FileSystem.MoveDirectory(dir, dir.Replace(sourceFilePath, Path.Combine(targetPath, praegeCodeNrFolderName)), true));
            }
        }

        public static void MoveFilesfromLocal(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string file in files)
            {
                FileInfo fi = new FileInfo(file);
                string filename = fi.FullName;
                
                TryAction(() => File.Move(filename, $"{Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(file))}"));
            }
        }

        public static void MoveFilesCode2fromLocal(string praegeCodeNrFolderName, string praegeCode2NrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCode2NrFileName + "*");

            foreach (string file in files)
            {
                FileInfo fi = new FileInfo(file);
                string filename = fi.FullName;
                
                TryAction(() => File.Move(filename, $"{Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(file))}"));
            }
        }

        public static void CopyDirectoryfromNetwork(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> dirs = Directory.EnumerateDirectories(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string dir in dirs)
            {
                TryAction(() => FileSystem.CopyDirectory(dir, dir.Replace(sourceFilePath, Path.Combine(targetPath, praegeCodeNrFolderName)), true));
                TryAction(() => FileSystem.DeleteDirectory(dir, DeleteDirectoryOption.DeleteAllContents));
            }
        }

        public static void CopyFilesfromNetwork(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string file in files)
            {
                FileInfo fi = new FileInfo(file);
                string filename = fi.FullName;
                
                TryAction(() => File.Copy(filename, $"{Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(file))}"));
                TryAction(() => File.Delete(file));
            }
        }
    }
}


Das Programm tut alles so wie vorher. Perfekt.
Und wenn es dadurch jetzt noch schneller ist dann hast du mir sehr geholfen.

@Ralf

Zitat:
Die Frage war auch ob es AllDirectories sein muss

Ich denke nicht.
Aber durch die Änderung die mir Th69 vorgeschlagen hat erübrigt sich das ja.

Vielen Dank für alles.

Grüße Tom
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Sa 25.06.22 08:26 
Jetzt verwendest du ja auch kein SearchOption.AllDirectories mehr, so daß jetzt (als Default) TopDirectoryOnly verwendet wird (und das sollte jetzt ja auch richtig sein, da du nur die Hauptordner durchsuchen solltest).

Gibt es denn jetzt einen Plan bei euch, wie ihr die 30000 Ordner wieder reduziert (da du ja geschrieben hast, daß sich diese "alten Daten angesammelt haben")? Für einen stabilen (und performanten) Dauerbetrieb deines Programms sollte das auf jeden Fall angegangen werden.

PS: Noch etwas ist mir aufgefallen:
Warum benutzt du
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
foreach (string file in files)
{
    FileInfo fi = new FileInfo(file);
    string filename = fi.FullName;
    // ...
}
?
In file steht doch schon der vollständige Pfadname!?! Du kannst also auf das FileInfo (Ressource-)Objekt komplett verzichten.

Und auf die String-Interpolation ($"{...}") bei
$"{Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(file))}" kannst du auch verzichten.

Das dir.Replace(...) ist auch nicht ganz optimal, da ja eigentlich nur der Pfadname am Anfang ersetzt werden soll (nicht auch noch innerhalb des Pfades).
Erzeuge am besten eine eigene Methode dafür:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
string ReplacePath(string path, string sourcePath, string destPath)
{
  // evtl. vorher noch mittels if (path.StartsWith(sourcePath)) überprüfen, sonst String.Empty oder Exception
   return destPath + path.Substring(sourcePath.Length);
}

(oder als Erweiterungsmethode in einer eigenen statischen Klasse, dann beim ersten Parameter noch this angeben).
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: So 26.06.22 00:12 
Hallo Th69,

Vielen Dank für deine Antwort,

Zitat:
Gibt es denn jetzt einen Plan bei euch, wie ihr die 30000 Ordner

Wie ich schon geschrieben hatte, wir das neue Programm, wenn es mal an den "Start geht" die Dateien und Ordner die kopiert werden danach gleich gelöscht.

Zitat:
PS: Noch etwas ist mir aufgefallen:
Warum benutzt du

Ich habe das so im Internet gefunden. Das so etwas nicht richtig ist, das erkenne ich nicht.

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:
namespace PDE
{
    internal static class IOFileOperations
    {
        public static void TryAction(Action action)
        {
            try
            {
                action();
            }
            catch (DirectoryNotFoundException ex)
            {
                ex.SaveErrorMessage();
            }
        }

        public static void MoveDirectoryfromLocal(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> dirs = Directory.EnumerateDirectories(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string dir in dirs)
            {
                TryAction(() => FileSystem.MoveDirectory(dir, dir.Replace(sourceFilePath, Path.Combine(targetPath, praegeCodeNrFolderName)), true));
            }
        }

        public static void MoveFilesfromLocal(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string filename in files)
            {                
                TryAction(() => File.Move(filename, Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(filename))));
            }
        }

        public static void MoveFilesCode2fromLocal(string praegeCodeNrFolderName, string praegeCode2NrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCode2NrFileName + "*");

            foreach (string filename in files)
            {               
                TryAction(() => File.Move(filename, Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(filename))));
            }
        }

        public static void CopyDirectoryfromNetwork(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> dirs = Directory.EnumerateDirectories(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string dir in dirs)
            {
                TryAction(() => FileSystem.CopyDirectory(dir, dir.Replace(sourceFilePath, Path.Combine(targetPath, praegeCodeNrFolderName)), true));
                TryAction(() => FileSystem.DeleteDirectory(dir, DeleteDirectoryOption.DeleteAllContents));
            }
        }

        public static void CopyFilesfromNetwork(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string filename in files)
            {                
                TryAction(() => File.Copy(filename, Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(filename))));
                TryAction(() => File.Delete(filename));
            }
        }
    }
}


Zitat:
Das dir.Replace(...) ist auch nicht ganz optimal,


Zitat:
Erzeuge am besten eine eigene Methode dafür:


Warum noch eine Methode?

Grüße Tom
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: So 26.06.22 09:00 
Ja, so sieht der Code doch schon viel aufgeräumter und lesbarer aus. Du mußt natürlich bei dir lokal dieses intensiv testen bzw. wenn du Tests auf dem Produktionsrechner machst, das Löschen ersteinmal auskommentieren. Ich hoffe, es gibt Sicherheitskopien der Daten? Ansonsten zieh dir lokal die Daten (oder wenigstens einige Tausend Unterordner davon) und teste damit.

Aber eine wichtige Änderung mußt du noch vornehmen (sonst verlierst du evtl. Daten!).
Und zwar bzgl. TryAction - beim Kopieren und anschließendem Löschen bei beiden Copy...fromNetwork-Methoden fängst du jetzt eine Exception einzeln ab (anstatt bei einer Exception beim Kopieren das Löschen nicht mehr durchzuführen). Daher mußt du beide Methoden-Aufrufe in einen Block packen (so wie auch dein Originalcode aussah):
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
TryAction(() => 
          {
             File/-System.Copy...(...);
             File/-System.Delete...(...);
          });

(wie du das am besten formatierst mußt du entscheiden bzw. entsprechend deiner VS-Einstellung).

Und eine extra Methode kostet nichts, sie macht den Code aber lesbarer, damit man später anhand des Namens noch erkennt, was diese Methode macht (und auch wegen der zusätzlichen Abfrage).

Dann wünsche ich dir jetzt, daß sich die Mühe ausgezahlt hat und das Programm dann seinen gewünschten Dienst leistet.
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Mo 27.06.22 08:28 
Guten Morgen Th69,

Vielen Dank für deine Antwort.

Funktioniert ist aber noch ein Fehler drin, leider ohne Fehlermeldung, weil eine Datei nicht kopiert wird.

Die Datei "Ch_22062415473.txt"(Beispiel) sollte mit diesem Code kopiert werden.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
 public static void MoveFilesfromLocal(string praegeCodeNrFolderName, string praegeCodeNrFileName, string sourceFilePath, string targetPath)
        {
            IEnumerable<string> files = Directory.EnumerateFiles(sourceFilePath, "*" + praegeCodeNrFileName + "*");

            foreach (string filename in files)
            {
                TryAction(() => File.Move(filename, Path.Combine(targetPath, praegeCodeNrFolderName, Path.GetFileName(filename))));
            }
        }


Es gibt 2 Unterschiede, dass bei dieser Datei "Ch_22062415473.txt" die Pfadtiefe 4 ist.
D:\S7_Export\Bosch\CH00\Prog_1 und das CH_ vor der Zahl steht.

Das sollte doch mit "*" + praegeCodeNrFileName + "*" kein Problem sein, oder?

Was ich auch komisch finde ist, dass bevor diese Datei "Ch_22062415473.txt" kopiert wird,
vorher die 6 Dateien aus diesem Ordner "D:\S7_Export\Sensopart\x015id02xa1" kopiert werden.
Da ich nichts anderes erkennen kann, denke ich, dass es die Pfadtiefe ist.
Ach ja und die Dateien, die dann nach der Datei "Ch_22062415473.txt" dran sind, werden kopiert.
Und was ganz wichtig ist, die Datei ist auch vorhanden, die kopiert werden soll. Ich habe es extra ein paar Zyklen laufen lassen.

Es werden alle Dateien und Ordner kopiert, bis auf diese eine. Es ist wie verhext.
Ich habe schon das GUI-Element überprüft. Die Arrays kontrolliert, ob ich vielleicht einen Eintrag vergessen habe.

Was denkst du, woran kann das liegen?

Zitat:
Aber eine wichtige Änderung mußt du noch vornehmen

Danke, habe ich geändert.

Zitat:
Dann wünsche ich dir jetzt, daß sich die Mühe ausgezahlt hat und das Programm dann seinen gewünschten Dienst leistet.

Vielen Dank hätte ich ohne euch auch nicht geschafft.

Grüße Tom
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4641
Erhaltene Danke: 1014

Win10
C#, C++ (VS 2015/17/19)
BeitragVerfasst: Mo 27.06.22 09:41 
Wird die Datei schon nicht von Directory.EnumerateFiles gefunden oder gibt es eine Exception beim Verschieben?
Bei ersterem überprüfe mal in der Konsole mit dir *22062415473*, ob diese aufgelistet wird (vorher ins Verzeichnis mit cd wechseln).

Und als sourceFilePath wird auch der volle Pfad "D:\S7_Export\Bosch\CH00\Prog_1" übergeben (nicht, daß es hier um ein Unterverzeichnis geht, da du - auch schon vorher in deinem Code - nur TopDirectoryOnly benutzt)?

Am besten, du debuggst mal den Code (oder läßt dir alle Pfade und Dateien mal ausgeben, s. Ablaufverfolgung und Debuggen in Visual C# - diese werden dann im VS-Ausgabefenster angezeigt).
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4643
Erhaltene Danke: 967


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 27.06.22 10:40 
Nebenbei zum ausprobieren. Man kann auch fast alle Framework Funktionen aus der Powershell benutzen und schauen was passiert wenn einem die Konsole in Visual Studio zu unsympatisch ist aber ansonsten gut mit der Shell unterwegs ist. In deinem Fall

ausblenden C#-Quelltext
1:
[IO.Directory]::EnumerateFiles("C:\MyLovelyPath""*MyLovelyFilter*")					

Für diesen Beitrag haben gedankt: Th69
UserTom Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 47



BeitragVerfasst: Mo 27.06.22 10:51 
Hallo Th69,

Danke für deine Antwort.

Also auf meinem Testsystem funktioniert es, also kann es nur noch an dem anderen System liegen.

Anbei 3 Dateien vom debuggen.

Vielleicht siehst du etwas, was falsch sein könnte.

"D:\S7_Export\Bosch\CH00\Prog_1"

TopDirectoryOnly ist Prog_1, oder? Wenn ja dann kann es nicht daran liegen.

Vorher wurde von hier kopiert "D:\S7_Export\Sensopart\x015id02xa1"

TopDirectoryOnly wäre x015id02xa1 ?


Grüße Tom
Einloggen, um Attachments anzusehen!