Zum Inhalt springen

C# , FileSystemWatcher


Eleu

Empfohlene Beiträge

Hallo,

ich möchte ein Verzeichnis dahingehend überprüfen, dass bei einer Änderung (Eine Datei wird hinzugefügt) ein Ereignis ausgelöst wird.

Jetzt habe ich ein Code Beispiel in VB.NET gefunden:

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

Ich habe es in C# umprogrammiert:

 private void Verzeichnis()
        {
            System.IO.FileSystemWatcher fsw = new System.IO.FileSystemWatcher();
            System.IO.WaitForChangedResult fswResult = new System.IO.WaitForChangedResult();
            fsw.Path = "C:\\PPS";
            fsw.Filter = "*.txt";
            fsw.NotifyFilter = System.IO.NotifyFilters.FileName;
            fsw.IncludeSubdirectories = false;
            fswResult = fsw.WaitForChanged(System.IO.WatcherChangeTypes.Created, 20000);
  
            //  Auswertung von fswResult: 
            if (fswResult.TimedOut)
            {
                //  Warten durch Timeout beendet 
                MessageBox.Show(("In den letzten 20 Sekunden wurde keine " + "Textdatei im Verzeichnis C:\\ angelegt."), "FileSystemWatcher: Timeout");
            }
            else
            {
                //  Warten durch Eintritt des Wartekriteriums beendet 
                MessageBox.Show(("Im Pfad "
                                + (fsw.Path + (" wurde die Textdatei "
                                + (fswResult.Name + " angelegt!")))), "TXT-Datei erzeugt!");
            }

        }

Ich rufe nun diese Methode alle 100ms über einen Timer auf und wenn ich eine *.TXT in das Verzeichnis "C:\\PPS" kopiere, erfolgt auch wie gewünscht darüber nach 20 Sek. eine Meldung.

Nur kann ich die MessageBox, die nach 20 Sek. erscheint nicht mit O.K. bestätigen und das übrige Programm hängt sich auf.

Ich vermute Mal, dass es wohl nicht so gedacht ist, dass ich die Methode zyklisch über einen Timer aufrufe, weil dem FileSystemWatcher ja auch schon eine Wartezeit übergeben wird.

Das Programm muss aber in eine Methode (Objekt) und eine Methode muss von außen angestoßen werden, sonst macht eine Methode nix?

Wie muss ich das machen, dass  es funktioniert?

Kann mir jemand helfen?

Gruß

Eleu

Bearbeitet von Eleu
Link zu diesem Kommentar
Auf anderen Seiten teilen

Beim FileSystemWatcher gibt es ein Event welches eintritt wenn sich bspw. eine Datei ändert o.Ä.

Siehe hierzu: https://msdn.microsoft.com/de-de/library/system.io.filesystemwatcher(v=vs.110).aspx den Abschnitt "Ereignisse"

Mal als Beispiel

        public class Playground
        {
            System.IO.FileSystemWatcher myFileSystemWatcher;

            private void foo()
            {
                myFileSystemWatcher = new System.IO.FileSystemWatcher();
                myFileSystemWatcher.Path = @"C:\PPS";
                myFileSystemWatcher.NotifyFilter = System.IO.NotifyFilters.LastAccess | System.IO.NotifyFilters.LastWrite
                                        | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName;

                myFileSystemWatcher.Filter = "*.txt";
                myFileSystemWatcher.Changed += new System.IO.FileSystemEventHandler(OnChanged);
                myFileSystemWatcher.EnableRaisingEvents = true;
                myFileSystemWatcher.IncludeSubdirectories = false;
            }

            private void OnChanged(object source, System.IO.FileSystemEventArgs e)
            {
                // Methodik
            }
        }

Des weiteren würde ich in dem Context keine Messagebox anzeigen sondern das ganze in einem anderen Context handeln.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Einen Timer brauchst du nicht. Der FileSystemWatcher besitzt Events, die implementiert werden können, um auf Änderungen in einem Ordner zu reagieren. Mal ein simples Beispiel einer Konsolenanwendung:

    class Program
    {
        private FileSystemWatcher watcher;

        public Program()
        {
            this.watcher = new FileSystemWatcher(@"D:\Test");
            this.watcher.Changed += (sender, e) => Console.WriteLine($"Changed: {e.Name}");
            this.watcher.Created += (sender, e) => Console.WriteLine($"Created: {e.Name}");
            this.watcher.Deleted += (sender, e) => Console.WriteLine($"Deleted: {e.Name}");
            this.watcher.Renamed += (sender, e) => Console.WriteLine($"Renamed: {e.OldName} => {e.Name}");
            this.watcher.EnableRaisingEvents = true;
        }

        static void Main(string[] args)
        {
            Program program = new Program();
            Console.ReadKey();
        }
    }

Nun werden alle Änderungen im Ornder D:\Test angezeigt

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo zusammen,

also ich kapiere es nicht.

Vielleicht habe ich auch etwas ganz wesentliches noch nicht verstanden.

Wenn ich eine Klasse erzeuge, oder eine Methode in der Form, dann muss ich doch in einer ereignisgesteuerten Programmiersprache, ein Ereignis nutzen (z.B.: Button Click) um einer Klasse Parameter zu übergeben. Ich bekomme dann, wenn nicht void, auch einen Rückgabewert zurück, den ich dann weiter verwenden kann.

Wenn es nun kein Timer ist, der zyklisch dieses Ereignis auslöst, mit welches Ereignis sage ich denn dann dem FileSystemWatcher, das er jetzt watchen soll um mir mitzuteilen, dass eine Änderung im Verzeichnis stattgefunden hat?

Ich habe einen Verdacht und zwar  gibt es bei mir im Projekt schon von Anfang an die Klasse Program.  Muss das da rein? Ist das eine Grundroutine die bei C# im Hintergrund automatisiert durchläuft.

Wie übergebe ich und wo in der Form, die Parameter der Klasse playground oder Program?

Gruß

Eleu

Link zu diesem Kommentar
Auf anderen Seiten teilen

O.k. habe es herausgefunden:

Damit geht es in der bestehenden Klasse Program:

class Program
    {
        private FileSystemWatcher watcher;

        public Program()
        {
            this.watcher = new FileSystemWatcher(@"C:\PPS");
            this.watcher.Changed += (sender, e) => MessageBox.Show("Eine Änderung");
      //      this.watcher.Created += (sender, e) => MessageBox.Show("Eine Änderung3"); 
      //      this.watcher.Deleted += (sender, e) => MessageBox.Show("Eine Änderung2");
            this.watcher.EnableRaisingEvents = true;
        }

        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {

            Program program = new Program();
  
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());

        }
    }

Danke.

 

Gruß

Eleu

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 19 Minuten schrieb Eleu:

Wenn es nun kein Timer ist, der zyklisch dieses Ereignis auslöst, mit welches Ereignis sage ich denn dann dem FileSystemWatcher, das er jetzt watchen soll um mir mitzuteilen, dass eine Änderung im Verzeichnis stattgefunden hat?

Aus diesem Grund finde ich es nicht gerade sinnvoll, dass Anfänger gleich mit einer grafischen Oberfläche anfangen, denn das Wissen ist einfach nicht vorhanden, wie Events eigentlich funktionieren.

Eine grafische Oberfläche läuft in einer Endlosschleife. In der Schleife werden jedes Mal die Eingabe entgegengenommen, verarbeitet und die Oberfläche neu gezeichnet. Ein Mausklick löst also im Grunde nicht das Event aus, sondern die Schleife befindet sich wieder an dem Punkt, wo sie die Eingabe überprüft wird und merkt, dass die Maustaste gedrückt wird. Schaut dann nach, ob ein Event implementiert wurde und wenn ja, dann wird die Implementierung aufgerufen. 

So ist es nun auch beim FileSystemWatcher. Es läuft eine Endlosschleife, die sich ein Stream mit Dateiänderungen anschaut und bei jedem Durchlauf wird geschaut, ob die letzte Dateiänderung mit deinen Filterkriterien, etc. übereinstimmt und dann schaut, ob das jeweilige Event implementiert wurde.

Den FileSystemWatcher kannst du auch in einer Form verwenden. Beispiel:

        public Form1()
        {
            InitializeComponent();
            FileSystemWatcher watcher = new FileSystemWatcher(@"D:\Test");
            watcher.Changed += (sender, e) => textBox1.Text = $"Changed: {e.Name}";
            watcher.Created += (sender, e) => textBox1.Text = $"Created: {e.Name}";
            watcher.Deleted += (sender, e) => textBox1.Text = $"Deleted: {e.Name}";
            watcher.Renamed += (sender, e) => textBox1.Text = $"Renamed: {e.OldName} => {e.Name}";
            watcher.SynchronizingObject = this;
            watcher.EnableRaisingEvents = true;
        }

Hierbei muss man aber wissen, dass die Endlosschleife in einem anderen Thread läuft als die Endlosschleife der grafischen Oberfläche und Änderungen an der UI darf nur der Thread der UI machen. Der FileSystemWatcher besitzt deswegen die Eigenschaft SynchronizingObject. Hier kann man das Objekt reinreichen, wer den FileSystemWatcher erzeugt hat und somit wird der Code über den UI-Thread ausgeführt.

Der FileSystemWatcher steht sogar in der Toolbox zur Verfügung und kann per Drag'n'Drop in die Form geschoben werden. Dabei wird der FilesystemWatcher folgendermaßen initialisiert:

            // 
            // fileSystemWatcher1
            // 
            this.fileSystemWatcher1.EnableRaisingEvents = true;
            this.fileSystemWatcher1.SynchronizingObject = this;
            this.fileSystemWatcher1.Changed += new System.IO.FileSystemEventHandler(this.fileSystemWatcher1_Changed);
            this.fileSystemWatcher1.Created += new System.IO.FileSystemEventHandler(this.fileSystemWatcher1_Created);
            this.fileSystemWatcher1.Deleted += new System.IO.FileSystemEventHandler(this.fileSystemWatcher1_Deleted);
            this.fileSystemWatcher1.Renamed += new System.IO.RenamedEventHandler(this.fileSystemWatcher1_Renamed);

Das, was ich im oberen Code gemacht habe, kann man sich auch generieren lassen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Whiz-zarD:

watcher.EnableRaisingEvents = true;

Nur als kleinen Hinweis noch, weil's mich beim ersten Mal etwas Zeit gekostet hat, um es rauszufinden: Das zitierte hier ist die Stelle, ab der der Watcher aktiv ist. Durch das reine Erzeugen etc. passiert erstmal gar nichts. Erst, wenn man das hier setzt, bekommt man die Events auch in der Anwendung.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 16 Stunden schrieb Whiz-zarD:

Aus diesem Grund finde ich es nicht gerade sinnvoll, dass Anfänger gleich mit einer grafischen Oberfläche anfangen, denn das Wissen ist einfach nicht vorhanden, wie Events eigentlich funktionieren.

Guten Morgen,

vor 15 – 20 Jahren habe ich größere Anwendungen, mit Visual Basic 6 geschrieben, und dann mit langer Unterbrechung, eigentlich nur noch sporadisch mal kleine Sachen. Gegenwärtig, versuche ich mich in eine sehr komplexe Anwendung, die ein Kollege von mir in C# geschrieben hat, einzuarbeiten. Um einen Einstieg hinzubekommen, habe ich mir zunächst selber kleinere Aufgaben gestellt und diese versucht mit VB.Net zu lösen. Das hat auch ganz gut geklappt, denn von der Syntax her besteht kein großer Unterschied zu VB6 und ich musste mich nur in der neuen Entwicklungsumgebung zurechtfinden. Jetzt versuche ich den Schritt in Richtung C# und, dank eurer Unterstützung, klappt das auch schon ganz gut. Parallel dazu habe ich auch ein Buch zum Nachschlagen.

Man mag meine Art, so zu lernen kritisch sehen, weil bei der schrittweisen Umsetzung, einige Grundlagen von C# fehlen, die dann dabei zur Stolperfalle werden.Das wird aber mit jeder neuen Umsetzung besser und so habe ich auch mal ein Erfolgserlebnis.

Jetzt wieder mit dem Hallo Welt Programm zu beginnen, wie ich es damals bei VB5 gemacht habe, wäre heute langweilig und ermüdend, weil vieles ja schon bekannt ist und dann gibt man vielleicht auf, weil es keinen Spaß macht..       

Vllt. kann das der Ein oder Andere ja verstehen?

 

Noch eine technische Frage:

 

Wenn ich aus einer Klasse heraus in eine TextBox schreiben wollte, würde ich eine Methode dafür in der Form programmieren:

 

  public void TextAnzeigen()
  {
            textBox1.Text = "Der Text";
  }

Nun könnte ich ja in der Klasse einfach diese Methode aufrufen, wenn ich nun die Form1 als Basisklasse dort angebe

 

    public class ResultWriter : Form1

Die Methode ist in der Klasse dann auch aufrufbar, doch es funktioniert nicht. Ich bekomme beim Start der Anwendung diese Fehlermeldung:

System.StackOverflowException: "Eine Ausnahme vom Typ "System.StackOverflowException" wurde ausgelöst."

und zwar an dieser Stelle in der Form:

 ResultWriter b = new ResultWriter(); 

Danach hängt sich sogar das ganze Visual Studio auf und startet neu. Darf eine Klasse nicht von Form1 erben? Wie kann ich aus einer Klasse heraus Methoden in der Form auslösen?

Gruß

Eleu

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 16 Minuten schrieb Eleu:

Die Methode ist in der Klasse dann auch aufrufbar, doch es funktioniert nicht. Ich bekomme beim Start der Anwendung diese Fehlermeldung:

System.StackOverflowException: "Eine Ausnahme vom Typ "System.StackOverflowException" wurde ausgelöst."

und zwar an dieser Stelle in der Form:

Lass mich raten: In deiner Form1 erzeugst du eine Instanz von deiner Klasse ResultWriter, richtig?
 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gerade eben schrieb KeeperOfCoffee:

Vermutlich Initialisierst du Form1 mit einem neuen ResultWriter, welcher ja ebenso wieder Form1 erbt. Somit erzeugst du ständig neue ResultWriter.

Das wäre auch meine erste Vermutung.
Das anhang der paar Code-Fetzen festzustellen ist aber schwer...

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 4 Minuten schrieb r4phi:

Okay.

Stell mal bitte den kompletten Code hier rein.
Aus einzelnen Code Fetzen ist es immer schwer irgendwelche Fehler zu finden...

Ja, kann ich machen. Was mir auffällt ist, dass sich im Projekt Mappen Explorer, das Symbol der Klasse ResultWriter  in eine Form Symbol ändert, sobald ich in der Klasse Form1 als Basisklasse bekannt mache.

Es ist ein Testprogramm, in dem ich auch diese Klasse, über ein Interface von anderen Klassenerbt.

Ich versuche das mal in einem ganz neuen Testprogramm.

 

Bearbeitet von Eleu
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 4 Minuten schrieb Eleu:

Ja, kann ich machen. Was mir auffällt ist, dass sich im Projekt Mappen Explorer, das Symbol der Klasse ResultWriter  in eine Form Symbol ändert, sobald ich in der Klasse Form1 als Basisklasse bekannt mache.

 

Du erbst schließlich von einer Form.
Entsprechend wird auch die davon abgeleitete Klasse eine Form.

Zudem ist mir nicht ganz klar was du damit bezwecken möchtest:

vor 28 Minuten schrieb Eleu:

public class ResultWriter : Form1

 

Wenn du deine ResultWriter Klasse in deiner Form verwenden möchtest solltest du das bspw. über Dependency Injection lösen. Wie bereits im vorherigen Thread diskutiert....

Edit:

Das Problem ist, wie auch schon im anderen Thread erwähnt, scheinbar gewisse Basics und ein gewisses Grundverständnis fehlt. Das sollte dringend nachgeholt werden

Bearbeitet von r4phi
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 40 Minuten schrieb Eleu:

versuche ich den Schritt in Richtung C# und, dank eurer Unterstützung, klappt das auch schon ganz gut. Parallel dazu habe ich auch ein Buch zum Nachschlagen.

 

Buch ist gut und schön, aber 

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/

dürfte dir kurz und knapp wohl mehr bringen.

Die paar Seiten durchzulesen dauert nicht so ewig und beantwortet meistens Fragen. Dazu ist auf nahezu jeder Seite ein oder mehrere Beispiele zur Veranschaulichung.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 37 Minuten schrieb Eleu:

Guten Morgen,

vor 15 – 20 Jahren habe ich größere Anwendungen, mit Visual Basic 6 geschrieben, und dann mit langer Unterbrechung, eigentlich nur noch sporadisch mal kleine Sachen.

Auch Visual Basic 6 ist Objektorientiert und die Forms funktionieren genauso, wie jede andere heutige grafische Oberfläche. Selbst Spiele funktionieren nach diesem Prinzip. Die Endlosschleife nennt sich dort Game Loop.

vor 40 Minuten schrieb Eleu:

Man mag meine Art, so zu lernen kritisch sehen, weil bei der schrittweisen Umsetzung, einige Grundlagen von C# fehlen, die dann dabei zur Stolperfalle werden.

Dir fehlen nicht nur die Grundlagen von C#, sondern die Grundlagen der Objektorientierung.

vor 42 Minuten schrieb Eleu:

Jetzt wieder mit dem Hallo Welt Programm zu beginnen, wie ich es damals bei VB5 gemacht habe, wäre heute langweilig und ermüdend, weil vieles ja schon bekannt ist und dann gibt man vielleicht auf, weil es keinen Spaß macht.. 

Aber offenbar hast du es schon damals nicht verstanden, denn ansonsten würden wir hier nicht sitzen und dir die Grundlagen der Objektorientierung zu erklären und diese Grundlagen sind erstmal sprachenunabhängig. Ich glaube auch nicht mal, dass du ein Hallo Welt-Programm vollständig erklären kannst. 

Mir ist nicht klar, was du mit einer Klasse ResultWriter erreichen willst, die zudem noch eine Form ist? ResultWriter klingt für mich eher nach eine Klasse, die irgendwas in ein Stream (z.B. Datei) schreibt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ein Hallo World ist natürlich langweilig, kann ich verstehen. Aber ich verstehe dennoch nicht, warum du dir gerade sowas wie FileSystemWatcher anguckst. Oder warum du generell was mit Forms machen willst.

Die Links die ich dir gepostet habe müssten dir eigentlich helfen, nochmal die Basics zu lernen. Du kannst problemlos jeden Teil dieser Grundlagen kurz in einer Console Application machen.

Es ist auch total egal wie viel du da programmierst, sondern das du das, was du gerade geschrieben hast verstehst. Du kannst 100 "Testprogramme" schreiben die funktionieren. Aber wenn du nicht in eigenen Worten erklären kannst, was du da gemacht hast und warum es funktioniert, hast du nicht wirklich was gelernt.

Gerade https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/object-oriented-programming wäre nochmal Pflicht.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn man aus einer Klasse heraus in eine TextBox schreiben möchte, geht das nicht über Vererbung von Form1,

sondern über using System.Windows.Forms;

Die Klasse:

using System.Windows.Forms;

namespace WindowsFormsApp1
{
        class Von_Klasse_in_TextBox
        {
            public Von_Klasse_in_TextBox()
        {
        }
          
        public void AktionAusführen()
        {
            Form1 form1 = Application.OpenForms[0] as Form1;
            form1.TextAnzeigen();
        }
        }
}

In der Form:

private void button5_Click(object sender, EventArgs e)
        {
            Von_Klasse_in_TextBox g = new Von_Klasse_in_TextBox();
            g.AktionAusführen();
        }

        public void TextAnzeigen()
        {
            textBox13.Text = "Der Text";
        }

Wird Button 5 betätigt, wird die Methode TextAnzeigen in der Form von der Klasse aus ausgeführt und schreibt den Text in die TextBox

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das "suchen" deiner Form bzw. die ganze Methode von "AktionAusführen" ist einfach nur unnötig. Genauso gibt es keine plausiblen Gründe das Zuweisen der Textbox.Text in eine Methode auszulagern. Die Zuweisung kann doch ohne Probleme im Click-Event stehen.

Allgemein solltest du der textbox auch keinen Hard-Coded Text übergeben, sondern der string sollte aus einer Methode deiner Klasse kommen.

KlasseText kText = new KlasseText();

textbox.Text = kText.GetText(Parameter ... );

Bearbeitet von KeeperOfCoffee
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 8 Minuten schrieb KeeperOfCoffee:

Das "suchen" deiner Form bzw. die ganze Methode von "AktionAusführen" ist einfach nur unnötig.

Ob das nun eine kluge Strategie ist, wenn man ein Programm entwickelt, steht ja auf einem ganz anderen Blatt Papier. Vielleicht begründest du deine Aussage, dann kann ich noch was dazu lernen.

Ich find es ehrlich schade, dass man mir die eigentliche Antwort auf meine Frage schuldig bleibt. Denn eine Antwort darauf habe ich ja nun selber nachgeliefert.

Mir ist schon klar, dass ich noch einiges nachzuholen habe, aber ich dachte immer, ein Forum wie dieses hier, ist dazu da, um Fragen zu stellen?

 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 4 Minuten schrieb Whiz-zarD:

Was genau möchtest du mit dem Code überhaupt erreichen? Wozu soll der gut sein? Was genau hast du dort vor?
Lass uns teilhaben an deinen Ideen. Nur so können wir dir auch helfen. Wie @KeeperOfCoffee schon sagt, der Code ist unnötig.

 

Es gibt kein übergeordnetes Ziel. Ich versuche das Ein oder Andere, um herauszufinden was man machen kann

Bearbeitet von Eleu
Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 1 Minute schrieb Eleu:

Ich find es ehrlich schade, dass man mir die eigentliche Antwort auf meine Frage schuldig bleibt. Denn eine Antwort darauf habe ich ja nun selber nachgeliefert.

Antwort auf welche Frage?

vor 2 Minuten schrieb Eleu:

Mir ist schon klar, dass ich noch einiges nachzuholen habe, aber ich dachte immer, ein Forum wie dieses hier, ist dazu da, um Fragen zu stellen?

Ich sehe aber hier keine Frage.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

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

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

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


Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

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

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...