Avatar billede zenny Nybegynder
10. november 2007 - 11:20 Der er 8 kommentarer og
1 løsning

Kopier flere filer på en gang / efter hinande - fileSystemWatcher

Hey experter.

Så jeg har kastet mig over et projekt, hvor jeg via fileSystemWatcher holder øje med en mappe, iden er at kopier nye filder der kommer ind i mappen over i en anden (en backup sikring), min kode virker glimerende når der kommer EN ny fil i mappen, men laver jeg flere på en gang får den stress og går ned.

Hvordan kopier jeg flere filer på en gang? eller nærmere efter hinanden?
Bliver jeg nød til at lave en buffer eller noget? og hvordan gør jeg det?

Min kode hvis det skulle være nødvendig:
      string path1;

        private void button1_Click(object sender, EventArgs e)
        {
            // make a new folderbrowser
            FolderBrowserDialog folderFrom = new FolderBrowserDialog();
 
            // Tjek if the dialog endet with a OK, and set the path.
            if (folderFrom.ShowDialog() == DialogResult.OK)
            {
                //MessageBox.Show(folderFrom.SelectedPath.ToString());
                textBox1.Text = folderFrom.SelectedPath.ToString();

                // set the filesystemwacher to keep en eye on the folder that we select.
                fileSystemWatcher1.Path = folderFrom.SelectedPath.ToString();
            }
        }

        // Sets the folder up where we want to move our files to, it works the same way as the "from folder"
        private void button2_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderTo = new FolderBrowserDialog();

            if (folderTo.ShowDialog() == DialogResult.OK)
            {
                //MessageBox.Show(folderTo.SelectedPath.ToString());
                textBox2.Text = folderTo.SelectedPath.ToString();
            }
        }

        private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
        {
            // Make a string with the compleat adress for our "copy to folder".
            path1 = textBox2.Text + "\\" + e.Name + ".txt";
         
            // Outputs whats found to logBox.
            logBox.Text += "\nFound a new file: " + e.Name;

            // Tjeks that there is a path to copy to.
            if (textBox2.Text != null)
            {
               
                File.Copy(e.FullPath.ToString(), path1, false);

                if (File.Exists(path1))
                {
                    logBox.Text += "\nCopy done";
                }
                else
                {
                    MessageBox.Show("Something went worng!");

                }
            }
        }
Avatar billede zenny Nybegynder
10. november 2007 - 12:09 #1
OKaay jeg er ved at rode lidt med en buffer, og det er med ret blandet succes.

Er det mulig at få
File.Copy(From, to, false);
Til at retunere når den er færdig med at kopiere ?
Avatar billede nielle Nybegynder
10. november 2007 - 13:03 #2
Måske noget i denne stil?

    class Program
    {
        private static string fromFolder = @"C:\Test1";
        private static string toFolder = @"C:\Test2";

        static void Main(string[] args)
        {
            FileSystemWatcher fileSystemWatcher1 = new FileSystemWatcher();

            fileSystemWatcher1.Path = fromFolder;
            fileSystemWatcher1.Created += new FileSystemEventHandler(fileSystemWatcher1_Created);
            fileSystemWatcher1.EnableRaisingEvents = true;

            Console.WriteLine("Press <enter> to exit");
            Console.ReadLine();
        }

        static void fileSystemWatcher1_Created(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine("Created: " + e.Name);

            string sourceFileName = Path.Combine(fromFolder, e.Name);
            FileInfo fi = new FileInfo(sourceFileName);

            ThreadPool.QueueUserWorkItem(MoveTo_callback, fi);
        }

        static void MoveTo_callback(object fiObj)
        {
            FileInfo fi = fiObj as FileInfo;

            Thread.Sleep(1000);

            string destFileName = Path.Combine(toFolder, fi.Name);
            fi.MoveTo(destFileName);
        }
    }
Avatar billede zenny Nybegynder
11. november 2007 - 10:10 #3
Well måske :). Først hvad gør?:

ThreadPool.QueueUserWorkItem(MoveTo_callback, fi);
og
FileInfo fi = fiObj as FileInfo;

Jeg tænkte lige på om
            Thread.Sleep(1000);
er den tid programmet venter med, indtil den kopiere den næste fil? i så fald hva så hvis det er en stor fil der tager mere end et sek at kopiere.
Avatar billede nielle Nybegynder
11. november 2007 - 10:25 #4
1) ThreadPool er en klasse som styre en pulje af tråde. Man kan give jobs til denne og de vil så blive udføret assynkront af resten af programmet. Jobbet der skal udføres er defineret i callback funktionen - her MoveTo_callback - og når denne er færdig med at køre lægges tråden tilbage i puljen.

2) Notationen:

FileInfo fi = fiObj as FileInfo;

svare egentlig blot til at typecase:

FileInfo fi = (FileInfo)fiObj;

forskellen er at der ikke smides en exception hvis variablen ikke kan castes til den angivne type - denne sættes blot til null i det tilfælde.

3) Thread.Sleep(1000) er ikke en pause mellem hver fil - disse kopieres via jobs som køre assynkront af hinanden. Det er derimod en pause som jeg har lagt ind for at sikre at det program som lægger filen i den første folder har nået at slippe den igen.

Faktisk er Thread.Sleep(1000) (= 1 sek) nok ikke den smarteste måde at gøre det på, man burde heller definere en løkke som hele tiden ser på hvornår der sidst er skrevet til filen. Første når denne tid holder op med at ændre sig er det fornuftigt at spekulere på om den kan flyttes.

4) Kopiering af en fil er faktisk ikke "bare" kopiering... Hvis du kopiere mellem to folder på de *samme* drev så er det kun referencen til hvor filen ligger som flyttes. Dette går lynhurtigt. Hvis de to mapper ligger på *forskellige* drev så skal selve filen flyttes/kopieres og det kan tage lang tid alt efter hvor stor filen egentlig er.
Avatar billede zenny Nybegynder
11. november 2007 - 14:45 #5
Okaaay ja, jeg har vist bare ik grundliggende nok viden om C#, fordi jeg forstår ik meget af hvad du lige skrev.

ThreadPool:
Hvad er en tråd? eller kan være.

Dvs. når ThreadPool får en række nye opgaver, fx flyt 100 filer, gør den det ved siden af selv main programmet, en efter en.


Det virker som en meget avanceret måde at gøre det hele på, kan det ikke gøres nemmere?x)
Avatar billede zenny Nybegynder
11. november 2007 - 14:48 #6
Det jeg mener med nemmere er, at mit simple program virker rigtig godt, så langt tid der bare kun kommer en fil ad gangen ind i den første mappe. Jeg tænkte så at jeg måske bare havde overset et eller andet, eller kunne tilføje en form for buffer, der så løse kopieringen en fil ad gangen.
Avatar billede nielle Nybegynder
11. november 2007 - 16:06 #7
Det er jo netop det der går galt – så længe filerne kommer i et fornuftigt tempo, er programmet hurtigt nok, men når de kommer væltende ind kan det ikke når at følge med. Der er ikke noget du har overset ... der skal simpelthen en anden struktur til.

Der er intet magisk ved tråde. Og det er bestemt hellere ikke er specielt C# begreb. Alle nogenlunde fornuftige programmeringssprog har dem. Odds er at du allerede har brugt dem uden at vide det.

Lidt om tråde og processer:

Når et program køres så afvikles det i en proces. Det er dem som du kan se i Joblisten i Windows. Enhver proces kan imidlertid være delt op i et antal tråde. En tråd er bare en delproces. CPU'en skifter imellem de forskellige tråde og derfor kan man sige at de køre side om side.

Hvorfor arbejde med tråde? Jo, hvis du f.eks. har en applikation med en GUI. Lad os desuden sige at du trykker på en knap, som sætter et tungt stykke regnearbejde i gang. Hvis dette regnearbejde bare får love til at køre videre i den tråd som håndtere brugergrænsefladen (og der er automatisk sådan en tråd) så vil den stjæle alle CPU kræfterne fra GUI'en. Resultatet er at GUI'en holder op med at reagere på at du trykker på knapper indtil at regnearbejdet er færdigt. Muligvis bliver der ikke en gang brugt kræfter på at gentegne brugergrænsefladen hvas den f.eks. har været dækket helt eller delvist af et andet vindue i mellem tiden – den er bare hvid der hvor det andet vindue har dækket.

Du kan læse mere her:

http://en.wikipedia.org/wiki/Thread_(computer_science)

Tilbage til dit problem:

Du har faktisk allerede en ekstra tråd her – fileSystemWatcher1_Created() kaldes nemlig i en anden tråd end hovedprogrammet.

Hvis du vil lave en løsning med en kø vil du får brug for endnu en tråd: fileSystemWatcher1_Created() putter filer i køen, og den anden tråd tager dem ud af køen en af gangen (flytter filerne). Du bliver nødt til at gøre det på den måde, for hvis du på nogen måde forsinker kaldet af fileSystemWatcher1_Created() vil det give dig den fejl du får nu. Kaldet af  fileSystemWatcher1_Created() skal simpelthen overstås så hurtig som overhovedet muligt.

I min skitserede løsning opnås dette ved at give jobbet med at kopiere filene videre til ThreadPool. Løsningen er faktisk ret simpel fordi at man så ikke behøver at tænke nærmere over at der er flere fil-kopieringer som er i gang på samme tid. Jeg vil faktisk vove at påstå at en løsning baseret på en kø (f.eks. en Queue) vil komme til at flyde mere.

Jeg ved ikke om jeg vil kalde løsningen for specielt avanceret, men er det i øvrigt ikke lige meget? Hvis den klare opgaven så er det vel det der skal til?
Avatar billede zenny Nybegynder
12. november 2007 - 15:43 #8
Fantastisk x), jeg har efterhånden arbejdet en del med computer, også C# i nogen tid, men jeg har ardrig hørt om tråde og hvordan de virker, men efter din forklaring kan jeg jo se at jeg allerede ved en del om den, og har også har haft en del problemer med den, og den problemstilling i mine egne programmer. Jeg har også tit set dem i joblisten, dog uden at tænke nærmere over det.

Jeg er stadig ikke helt med på hvordan jeg bruger threads i C#, men det tror jeg nu nok der skal komme. Det vigtigeste er den viden denne forums-tråd har givet mig, og er bestemt alle points værd, så smid endelig et svar :)
Avatar billede nielle Nybegynder
12. november 2007 - 22:03 #9
Svar :^)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester