none
Ordner, Dateien, verschieben RRS feed

  • Frage

  • Hallo,

    -<MOVEFILES destinationpath="C:\Trace_To_Move" filter="*.tra, *.text, *.log" sourcepath="C:\Trace" 
    ich suche Ansätze, wie ich folgendes im Hintergrund abarbeiten lassen kann.
      Im Verzeichnis sollen Daten zyklisch (ca. alle 60 Sekunden) verschoben werden mit Extension.
      Fehler vom Anwender.
       Config
         A)destinationpath="C:\Trace_To_Move"
     
         B)destinationpath="C:\Trace_To_Move\"
           Mal mit \ mal ohne \, so wird es teils eingegeben.
         Neues File mit Ausgabe der Verschiebung "C:\Trace_To_Move\LogMove.txt"
                        Inhalt, nur Zeit und Anzahl der Dateien.
                
      Wie kann ich beides abfangen?
      Danke für die Unterstützung.
    Viele Grüße Ulrich


     
    Dienstag, 16. Februar 2016 17:15

Antworten

  • Hi Ulrich,
    GetFiles verkraftet nur ein Pattern. Da kann man nicht wie beim OpenFileDialog mehrere Pattern angeben. Wenn es Dir nicht gelingt, mit einem Pattern incl. * und ? alle gewünschten Dateien zu erreichen, dann musst Du über eine Schleife alle Pattern nacheinander abarbeiten.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert Ulrich Stippe Sonntag, 21. Februar 2016 14:44
    Samstag, 20. Februar 2016 13:28
  • Hi Ulrich,
    lock schaut nach, ob das Objekt in Nutzung ist. Wenn ja, dann muss der Thread warten bis es wieder freigegeben wird. Von welchem Typ das Objekt ist, ist egal. Wichtig ist, dass alle gegenseitig blockierenden lock's dasselbe Objekt nutzen. Wenn das Lock-Objekt in unterschiedlichen Objekten instanziiert wird, dann wird natürlich nicht gegenseitig blockiert.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert Ulrich Stippe Dienstag, 23. Februar 2016 17:31
    Dienstag, 23. Februar 2016 17:26
  • Hallo Ulrich,

    keine der Varianten. Da musst Du dir bspw. ein Stringarray oder eine List<String> anlegen und dann mit einer Schleife alle Filter durchlaufen. Bspw. so:

    String[] filters = { "*.log", "*.txt" };
    
    List<System.IO.FileInfo> files = new List<System.IO.FileInfo>();
    foreach( String filterItem in filters ) {
        files.AddRange( new System.IO.DirectoryInfo( @"X:\Ordner\" ).GetFiles( filterItem, System.IO.SearchOption.TopDirectoryOnly ) );
    }
    


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Ulrich Stippe Sonntag, 21. Februar 2016 14:44
    Samstag, 20. Februar 2016 13:20
    Moderator

Alle Antworten

  • Hallo Ulrich,

    prüf doch einfach, ob ein \ am Ende steht und falls nicht, füg den \ ein.

    if( !obj.DestinationPath.EndsWith( @"\" )
        obj.DestinationPath += @"\";
    


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Dienstag, 16. Februar 2016 17:19
    Moderator

  • if( !obj.DestinationPath.EndsWith( @"\" )
        obj.DestinationPath += @"\";
    



    Hallo Stefan,

    ja stimmt;-)

     Noch einen guten Tipp für das Analysieren, Threading?

       Evtl. mit BackgroundWorker und StopWatch?

    Gruß, Ulrich

    Dienstag, 16. Februar 2016 17:28
  • Hi,

    FileSystemWatcher?

    Alternativ einen Timer einbauen und dann prüfen, ob es was zu tun gibt. Falls ja, gibt es verschiedene Ansätze. Await, BackgroundWorker, ... Schau einfach mal hier:

      https://msdn.microsoft.com/de-de/library/kztecsys.aspx

      http://stackoverflow.com/questions/29013958/how-to-implement-an-async-file-delete-create-move


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Dienstag, 16. Februar 2016 17:45
    Moderator
  • Hallo zusammen,

    ich würde hier Path.Combine nutzen. Das ist speziell für diese Aufgabe da und prüft auch auf den \ am Ende vom Ordnerpfad.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Dienstag, 16. Februar 2016 19:03
    Moderator
  • ich würde hier Path.Combine nutzen. Das ist speziell für diese Aufgabe da und prüft auch auf den \ am Ende vom Ordnerpfad.


    Hallo Tom,

    ja stimmt, deshalb frage ich nach.

    Noch einen anderen Tipp zum Verschieben der Files neben dem Hauptprozess?

    Viele Grüße Ulrich

    Dienstag, 16. Februar 2016 20:22
  • Hi Ulrich,
    im Hintergrund zu arbeiten geht einfach mit dem BackgroundWorker oder einfach nur in einem Thread. Welche konkrete Frage hast Du da?

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Dienstag, 16. Februar 2016 20:35
  • Welche konkrete Frage hast Du da?


    Hallo Peter,

    ich hab's so gelöst.
    Es tut. Wenn Du noch was weißt, gerne. Bin offen.

    Grüße Ulrich

     Stopwatch stopWatch = new Stopwatch();
                stopWatch.Start();
                TimeSpan ts;
    
                while (!bw.CancellationPending)
                {
                    System.Threading.Thread.Sleep(50);
                    ts = stopWatch.Elapsed;
                    if (ts.Seconds > bw.Interval)
                    {
                        stopWatch.Stop();
                        System.Diagnostics.Debug.Assert(this == bw);
          
                        System.IO.FileInfo[] files = new System.IO.DirectoryInfo(bw.SourcePath).GetFiles(bw.Filter,
                            System.IO.SearchOption.TopDirectoryOnly);
    
                        foreach (System.IO.FileInfo file in files)
                        {
                            File.Move(file.FullName, bw.DestinationPath + "\\" + file.Name);
                        }
                        stopWatch.Restart();
                    }
                }

    Mittwoch, 17. Februar 2016 17:42
  • Hi Ulrich,
    was Du da mit der Stoppuhr machst, erschließt sich mir nicht. Im DoWork des BackgroundWorker reicht eine einfache Schleife um Move mit einer Abfrage, ob die Schleifen zu beenden ist (Abbruch-Wunsch).


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Mittwoch, 17. Februar 2016 20:18
  • Hallo Peter,

    ich möchte alle 60 Sekunden (bw.Interval) die Dateien verschieben.

     foreach (System.IO.FileInfo file in files)
                        {
                            File.Move(file.FullName, bw.DestinationPath + "\\" + file.Name);
                        }
    

    Alle Files im Ordner verschieben, deshalb zweite Schleife.

    Du kann es gerne optimiert veröffentlichen.

    Alle 60 Sekunden soll eine Überprüfung stattfinden, solange die App.EXE läuft.

    Viele Grüße Ulrich

    Mittwoch, 17. Februar 2016 21:12
  • Hallo Ulrich,

    nimm doch, wie ich es schon vorgeschlagen hatte, einen Timer und kein Konstrukt mit Thread.Sleep. Das ist absolut unnötig und bringt dir keinen einzigen Vorteil, dafür aber viele Nachteile.

      https://msdn.microsoft.com/de-de/library/system.timers.timer.aspx

    Einen Überblick über die verfügbaren Timer Klassen findest Du bspw. hier:

      http://robertgreiner.com/2010/06/using-stopwatches-and-timers-in-net/

    Eine Stopwatch dient zum Messen der vergangenen Zeit, nicht zum Basteln von Konstrukten, die periodisch ausgeführt werden sollen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community



    Mittwoch, 17. Februar 2016 21:33
    Moderator
  • Hallo Stefan,
    ich habe es jetzt so gelöst.
    Problem ist das Beenden, TimerMovingFiles.Change(0, 0);
    Reicht das?
    Über einen kurzen Kommentar, Verbesserung bedanke ich mich.

    Viele Grüße Ulrich

      private static System.Threading.Timer TimerMovingFiles;
            private TimerCallback CallbackTimerMovingFiles;
            private struct StructMoveFiles
            {
                public string SourcePath;
                public string DestinationPath;
                public string Filter;
            }
    
            //using System.Threading; 
            public void RunTimerMovingFiles(string sourcePath, string destinationPath, int interval, string filter)
            {
                StructMoveFiles objMoveFiles;
                objMoveFiles.SourcePath = sourcePath;
                objMoveFiles.DestinationPath = destinationPath;
                objMoveFiles.Filter = filter;
    
                int timeout = Timeout.Infinite;
                CallbackTimerMovingFiles = new TimerCallback(RunEvent);
                TimerMovingFiles = new Timer(CallbackTimerMovingFiles, objMoveFiles, timeout, interval * 1000);
                TimerMovingFiles.Change(0, interval * 1000); // change the time, to stop ist, break use both the same value
            }
    
    
            public void RunEvent(object state)
            {
                //Trace.WriteLine("RunEvent() called at " + DateTime.Now.ToLongTimeString());
                StructMoveFiles stateMoveFiles = (StructMoveFiles)state;
                System.IO.FileInfo[] files = new System.IO.DirectoryInfo(stateMoveFiles.SourcePath).GetFiles(stateMoveFiles.Filter,
                           System.IO.SearchOption.TopDirectoryOnly);
    
                foreach (System.IO.FileInfo file in files)
                {
                    if (File.Exists(file.FullName))
                        File.Move(file.FullName, stateMoveFiles.DestinationPath + "\\" + file.Name);
                }
            }

    Donnerstag, 18. Februar 2016 17:19
  • Hi Ulrich,
    zum Beenden des Zeitgebers würde ich anstelle Change besser Dispose benutzen. Außerdem sollte die Methode RunTimerMovingFiles gegen wiederholtes Aufrufen blockiert werden, solange der Timer noch aktiv ist.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Samstag, 20. Februar 2016 05:39

  • zum Beenden des Zeitgebers würde ich anstelle Change besser Dispose benutzen. Außerdem sollte die Methode RunTimerMovingFiles gegen wiederholtes Aufrufen blockiert werden, solange der Timer noch aktiv ist.

    Guten Morgen Peter,

    ja stimmt, wie macht man das am besten? bool Flag?

    Beenden nur das aufrufen?TimerMovingFiles.Dispose()?

    Grüße Ulrich

    Samstag, 20. Februar 2016 08:36
  • Hi Ulrich,
    hier mal eine Konsolen-Demo, wie ich das machen würde. Ich hoffe, ich habe alle Möglichkeiten abgefangen.

    using System;
    using System.Threading;
    
    namespace ConsoleApplication1CS
    {
      class Program14
      {
        static void Main(string[] args)
        {
          Program14Demo c = new Program14Demo();
          c.RunTimerMovingFiles(@"c:\temp", @"c:\temp1", 1, "*.*");
          Thread.Sleep(5000);
          c.StopMovingFiles();
          c.RunTimerMovingFiles(@"c:\temp", @"c:\temp1", 1, "*.*");
          Thread.Sleep(200);
          c.RunTimerMovingFiles(@"c:\temp", @"c:\temp1", 1, "*.*");
          Thread.Sleep(2000);
          c.StopMovingFiles();
          Console.Read();
        }
    
    
      }
    
      class Program14Demo
      {
        private static System.Threading.Timer TimerMovingFiles;
        private TimerCallback CallbackTimerMovingFiles;
        private Status Zustand = Status.Stopped;
        private object locking = new object();
    
        private struct StructMoveFiles
        {
          public string SourcePath;
          public string DestinationPath;
          public string Filter;
        }
    
        //using System.Threading; 
        public void RunTimerMovingFiles(string sourcePath, string destinationPath, int interval, string filter)
        {
          lock (locking)
          {
            if (Zustand != Status.Stopped)
            {
              Console.WriteLine("Kopieren ist in Arbeit");
              return;
            }
            Zustand = Status.Waiting;
            Console.WriteLine("Kopieren wird gestartet");
          }
    
          StructMoveFiles objMoveFiles;
          objMoveFiles.SourcePath = sourcePath;
          objMoveFiles.DestinationPath = destinationPath;
          objMoveFiles.Filter = filter;
    
          CallbackTimerMovingFiles = new TimerCallback(RunEvent);
          TimerMovingFiles = new Timer(CallbackTimerMovingFiles, objMoveFiles, 0, interval * 1000); // sofort starten
        }
    
        public void StopMovingFiles()
        {
          lock (locking)
          {
            if (TimerMovingFiles == null) return; // es war kein RunTimerMovingFiles
            TimerMovingFiles.Dispose();
            TimerMovingFiles = null;
            Console.WriteLine("Kopieren gestoppt");
          }
        }
    
        public void RunEvent(object state)
        {
          try
          {
            lock (locking)
            {
              if (Zustand == Status.Working)
              {
                Console.WriteLine("vorheriger Kopiervorgang ist noch in Arbeit");
                return;
              }
              Zustand = Status.Working;
            }
            //Trace.WriteLine("RunEvent() called at " + DateTime.Now.ToLongTimeString());
            StructMoveFiles stateMoveFiles = (StructMoveFiles)state;
            System.IO.FileInfo[] files = new System.IO.DirectoryInfo(stateMoveFiles.SourcePath).GetFiles(stateMoveFiles.Filter,
                       System.IO.SearchOption.TopDirectoryOnly);
            foreach (System.IO.FileInfo file in files)
            {
              if (TimerMovingFiles == null) break;
              Console.WriteLine(file.FullName);
              //if (File.Exists(file.FullName))
              //  File.Move(file.FullName, stateMoveFiles.DestinationPath + "\\" + file.Name);
              Thread.Sleep(300); // Simulation der Kopierdauer
            }
          }
          catch (Exception ex)
          {
            Console.WriteLine($"Fehler: {ex.Message}");
          }
          finally
          {
            this.Zustand = Status.Waiting;
            if (TimerMovingFiles == null) this.Zustand = Status.Stopped;
          }
        }
    
        private enum Status
        {
          Stopped,
          Waiting,
          Working,
        }
      }
    }

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut




    Samstag, 20. Februar 2016 10:30
  • Hallo Peter,

    sieht gut aus. Vielen Dank. Der Status war hilfreich.

    Letzte Frage, was ist korrekt, damit die Funktion bezgl. Filter es korrekt macht?

      Filterschreibweise

        filter="*.tra, *.text, *.log"

        filter="*.tra | *.text | *.log"

    Oder wie machst Du das gewöhnlich?

    Grüße Ulrich

    Samstag, 20. Februar 2016 12:51
  • Hallo Ulrich,

    keine der Varianten. Da musst Du dir bspw. ein Stringarray oder eine List<String> anlegen und dann mit einer Schleife alle Filter durchlaufen. Bspw. so:

    String[] filters = { "*.log", "*.txt" };
    
    List<System.IO.FileInfo> files = new List<System.IO.FileInfo>();
    foreach( String filterItem in filters ) {
        files.AddRange( new System.IO.DirectoryInfo( @"X:\Ordner\" ).GetFiles( filterItem, System.IO.SearchOption.TopDirectoryOnly ) );
    }
    


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Ulrich Stippe Sonntag, 21. Februar 2016 14:44
    Samstag, 20. Februar 2016 13:20
    Moderator
  • Hi Ulrich,
    GetFiles verkraftet nur ein Pattern. Da kann man nicht wie beim OpenFileDialog mehrere Pattern angeben. Wenn es Dir nicht gelingt, mit einem Pattern incl. * und ? alle gewünschten Dateien zu erreichen, dann musst Du über eine Schleife alle Pattern nacheinander abarbeiten.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert Ulrich Stippe Sonntag, 21. Februar 2016 14:44
    Samstag, 20. Februar 2016 13:28
  • Hallo Zusammen,

    Danke Euch allen.

    1 Punkt dennoch.

     private object locking = new object();
    

    Das Objekt locking benötige ich lediglich wegen dem Thread (Timer).

    Was ist aber der Hintergrund. Könnt Ihr mir das noch erklären. DANKE.

    Grüße Ulrich

    Montag, 22. Februar 2016 17:50
  • Hi Ulrich,
    genau!

    Die Wahrscheinlichkeit, dass das gebraucht wird ist sehr gering. Wenn aber beispielsweise aus Lastgründen der nächste Timer-Tick genau zwischen Prüfung und Zuweisung kommt, dann gibt es einen Fehlablauf. Besser ist es, solche Abläufe zu verriegeln. Außerdem kann es später bei Umbau des Programmes passieren, dass die Methode auch anders aufgerufen wird, so dass die Wahrscheinlichkeit des Fehlablaufes steigt, und wenn das Verriegeln dann vergessen wird, dann sucht man u.U. sehr lange, da das Problem vielleicht nur bei einem Anwender auftritt, der vielleicht nur einen Kern zur Verfügung hat (beispielsweise in einer VM).


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Montag, 22. Februar 2016 18:31
  • Hallo Peter,
    doch noch eine kleine kurze Verständnisfrage.
    Sicher benötige ich dass Objekt für den Thread.
    Aber was macht das konkret, wieso passiert dann nichts unvorhersehbares.
    Was ist jedoch die Aufgabe von lockObject? Ist ja irgendwie ein leeres Objekt.
    Kann man das in wenigen Worten erklären?
    Oder anders gesagt, könnte ich als Objekt einfach einen string oder ein
    anderes Objekt nehmen?
    Viele Grüße Ulrich
    Dienstag, 23. Februar 2016 17:06
  • Hi Ulrich,
    lock schaut nach, ob das Objekt in Nutzung ist. Wenn ja, dann muss der Thread warten bis es wieder freigegeben wird. Von welchem Typ das Objekt ist, ist egal. Wichtig ist, dass alle gegenseitig blockierenden lock's dasselbe Objekt nutzen. Wenn das Lock-Objekt in unterschiedlichen Objekten instanziiert wird, dann wird natürlich nicht gegenseitig blockiert.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert Ulrich Stippe Dienstag, 23. Februar 2016 17:31
    Dienstag, 23. Februar 2016 17:26
  • Von welchem Typ das Objekt ist, ist egal. Wichtig ist, dass alle gegenseitig blockierenden lock's dasselbe Objekt nutzen. Wenn das Lock-Objekt in unterschiedlichen Objekten instanziiert wird, dann wird natürlich nicht gegenseitig blockiert.

    Hallo Peter,

    das wollte ich wissen, jetzt passt es. Danke.

    Grüße Ulrich

    Dienstag, 23. Februar 2016 17:31