Automatyczny folder

No no somekind odwaliłeś kawał dobrej roboty !!

Wszystko pięknie działa, widać że są nowe przyciski w głównym oknie programu i ikonka w trayu.

Nawet jest możliwość zapisania ustawień i ich wczytania! :o

Bardzo dziękuję użytkownikowi somekind za:

  • Stworzenie w ogóle tego programu

  • Za ulepszoną wersję 2.0

  • Za poprawioną wersję 2.1

=D =D =D =D =D =D =D =D =D =D =D

Mam nadzieję, że kiedyś na pewno będą lepsze wersje, ale na razie pracować będe na wersji 2.0 :smiley:

Ok oto na szybko napisana wersja w Perlu, wiem że konfiguracja programu przez edycję źródła to barbarzyństwo, ale za to ile pracy mniej :slight_smile: Skrypt wymaga, aby wszystkie podane katalogi już istniały, inaczej przerwie pracę.

#!/usr/bin/perl


use strict;

use warnings;

use File::Spec::Functions qw(catdir);


my $monitored_dir = catdir( $ENV{HOME}, 'programowanie', 'perl_dir_monitor' );


my %ext2patch = (

					ogg => catdir( $monitored_dir, 'music' ),

					txt => catdir( $monitored_dir, 'documents' ),

					cpp => catdir( $monitored_dir, 'sources' )

				);


my $interrupted = 0;


$SIG{'INT'} = sub { ++$interrupted };


sub file_ext

{

	my($file_ext) = ($_[0] =~ /.*\.(.*)$/);

	return $file_ext || '';

}


chdir $monitored_dir or die "Nie można zmienić katalogu na $monitored_dir: $!\n";


while(1)

{

	my @files = grep { -f } <*>;


	for my $file (@files)

	{

		die "Przerwano wykonywanie skryptu $0\n" if $interrupted;

		my $ext = file_ext($file);

		next unless exists $ext2patch{$ext};

		rename $file, catdir( $ext2patch{$ext}, $file ) or die "Nie udało się przenieść pliku $file: $!\n";

	}

	sleep 1;

}

// edit: znalazłem co najmniej 1 błąd w powyższym kodzie, ciekawe czy ktoś go zauważy? :>

// edit2:skrypt raczej nie jest do użytku, napisałem nas szybko tylko po to, żeby pokazać piękno i zwięzłość perla :slight_smile: Trzeba by było jeszcze dopisać zmianę nazwy pliku w razie istnienia pliku o takiej nazwie w docelowym katalogu i pomyśleć nad tysiącem innych rzecz, np. uprawnieniami do plików.

To była wersja robiona na szybko, prawie na kolanie :slight_smile: Tylko nie wiem, czy jest to coś złego. Myślę, że dodawanie oddzielnej klasy tylko do operacji na plikach byłoby w tym przypadku rozwiązaniem bardzo na siłę. Wszak tylko w odpowiedzi na zdarzenia z głównego okna te metody są wywoływane.

Natomiast w wersji drugiej mam oddzielną klasę (z dwiema metodami do zapisu i odczytu konfiguracji), bo potrzebują jej zarówno proces chodzący w trayu, jak i okienko konfiguracyjne - i wówczas takie rozdzielenie ma sens.

Zawsze o tym zapominam. Tzn. raptem drugi raz, bo wcześniej napisałem tylko jeden program z takim bajerem jak okienko konfiguracyjne wywoływane z ikonki w trayu. Uwaga - konkurs - kto poda jego nazwę stawiam piwo albo colę :slight_smile: (w zależności od wieku).

To też już naprawione - za dużo metody Kopiego-Pejsta użyłem i nawet konfiguracja się przestała automatycznie zapisywać.

SOA#1 :smiley:

A tak na serio - wpisujesz rozszerzenia z kropką, czy bez? Bo ja wcześniej nie przewidziałem opcji z.

Tak czy siak - wielkie dzięki za poświecenie czasu i zwrócenie uwagi na błędy.

Ależ nie ma za co :slight_smile:

Poprawiona wersja tutaj: http://www.somekind.pl/_upload/AutoFileMoveSetup.2.1.exe

Wiesz - jakby mój kod okroić z interfejsu, interakcji z użytkownikiem i konfiguracji (oraz wiążącego się z nią sprawdzania danych wprowadzanych przez użytkownika), to wyglądałby tak:

using System;

using System.Collections.Generic;

using System.IO;


namespace EasyAutoFileMove

{

    class Program

    {

        static private Dictionary ext2path = new Dictionary();


        static void Main(string[] args)

        {

            ext2path.Add(".mp3", "D:/Temp/Nowa Muza");

            ext2path.Add(".jpg", "D:/Temp/Nowe Obrazy");

            ext2path.Add(".avi", "D:/Temp/Nowe Wideo");


            FileSystemWatcher fsw = new FileSystemWatcher(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "/test");

            fsw.Created += new FileSystemEventHandler(fsw_Created);

            fsw.EnableRaisingEvents = true;


            Console.WriteLine("Wystartowałem!");

            Console.ReadLine();

        }


        static void fsw_Created(object sender, FileSystemEventArgs e)

        {

            while (true)

            {

                try

                {

                    string targetDir = String.Empty;

                    if (ext2path.TryGetValue(Path.GetExtension(e.FullPath), out targetDir))

                        File.Move(e.FullPath, Path.Combine(targetDir, e.Name));

                    break;

                }

                catch

                {

                    System.Threading.Thread.Sleep(100);

                }

            }

        }

    }

}

Więc długość porównywalna z Twoim, a w zasadzie nawet krótsza, jeśli policzyć jedynie instrukcje. Ty masz za to mniej klamerek, bo nie musisz mieć przestrzeni nazw i klasy :stuck_out_tongue:

Błędu w Twoim kodzie nie znajdę, bo perla nie znam. Ale mam pytania dwa:

  1. Jak rozumiem co sekundę w pętli listujesz sobie zawartość katalogu. A jeśli chcielibyśmy monitorować także podkatalogi tego katalogu? Wywoływałbyś taką funkcję rekurencyjnie? Jaki miałoby to wpływ na wydajność?

  2. Jak zachowa się ten skrypt, gdy do katalogu zacznie się kopiować duży plik? Czy nie będzie tak, że zostanie wykryte jego pojawienie się, a następnie program się zatnie w momencie próby skopiowania (bo nie będzie miał dostępu do pliku, który jest utworzony, ale trwa do niego zapis)?

Bo ten while u mnie służy właśnie do uniknięcia tego problemu - dość ważnego moim zdaniem.

Cashext - stawiasz piwo jak się spotkamy :wink:

od samego początku wpisywałem bez, spróbuję raz jeszcze jutro

Odnośnie tamtej uwagi, nie traktuj jej za przytyk, sam pewnie też bym napisał w ten sposób, chociaż ostatnio staram się odseparować od siebie wszystko co się da.

I pamiętaj, że program działa po uruchomieniu, nic nie zrobi z plikami, które były w katalogu wcześniej.

A gdy będziesz próbował użyj już nowej wersji.

Nie traktuję jako przytyk, każda konstruktywna krytyka jest dobra, zwłaszcza jeśli może prowadzić do rozwoju jakiejś sensownej dyskusji.

Ja w zasadzie robię to tak, że jak ilość kodu dodatkowego przeważa nad ilością kodu interfejsu, to przerzucam to do dodatkowej klasy, będącej jakby “silnikiem” dla formatki. W tym przypadku, to raptem kilka linijek i nie było sensu.

Co Ty tu robisz, skoro sam o sobie piszesz, że nie jesteś i nie będziesz programistą? ;>

A tak się szwendam :slight_smile: Miałem na myśli, że nie planuje swojej przyszłości jako programista, co nie znaczy, że nie mam jakiegoś doświadczenia, czy też od poniedziałku nie pracuje jako takowy :stuck_out_tongue: Po prostu nie jest to chyba moje powołanie :wink:

Dzięki somekind.

Mam nadzieję, że ta wersja będzie szybsza i stabilniejsza.

Teraz będę pracować na tej wersji :smiley: :smiley:

Bym zapomniał.

oczywiście tutaj był problem, pliki testowe przygotowałem wcześniej. Teraz wszystko jest tak jak być powinno :slight_smile:

Ad1. Monitorowanie podkatalogów trzeba by było dopisać, ten skrypt bierze pod uwagę tylko pliki znajdujące się bezpośrednio w monitorowanym katalogu.

Ad2. Racja, to też trzeba wziąć pod uwagę, spróbowałem u mnie na 1,1GB archiwum i… działało. Sam byłem zdziwiony. Zacząłem kopiować do monitorowanego katalogu, skrypt przeniósł plik i kopiowanie dokończyło się do katalogu po przeniesieniu, wszystko działało. I wstyd się przyznać ale wiem czego to zasługa - ext3 czy GIO, czy może ogółem to działa pod GNU/Linux albo i wszystkimi Unix-like.

Napisałem ten skrypcik na szybko, ale problem jest bardziej skomplikowany niż by się wydawało.

Osobiście gdybym musiał robić taki program to robiłbym go raczej z użyciem GIO (http://library.gnome.org/devel/gio/stable/ch01.html). Plusem jest, że program pisany w C/C++ działałby jako osobny proces niezależny od interpretera Perla / środowiska uruchomieniowego .NET - to jest wada, bo działanie programu jest zależne od działania środowiska uruchomieniowego.

Tak ogółem gdyby się zastanowić to trzeba brać pod uwagę dużo czynników, wymienię kilka rzeczy które przyszły mi do głowy, mam nadzieję, że okażą się przydatne:

  • jak już wspomniałeś - podkatalogi, co z nimi?

  • tworzyć katalogi podane przez użytkownika jeśli nie istnieją?

  • co z plikami/katalogami do których użytkownik nie ma dostępu, nie ma praw do zapisu?

  • co z dowiązaniami (pod Windows: skróty) - przenosić skrót czy plik na który wskazuje?

  • no i problem kiedy plik jest dopiero tworzony i trwa to długo

  • istotną jest kwestia przechwytywania sygnałów aby nie przerwać działania aplikacji w połowie przenoszenia pliku

Choć znając życie to wcale nie koniec problemów :slight_smile: Nie wspominam już o różnych systemach plików, odmontowaniu monitorowanego katalogu (np. gdyby znajdował się na pendrive) itp. itd…

Ciekawy program, sam też pisze programy w visual c# :wink:

Znalazłem małe niedopatrzenie w twoim, a mianowicie w instalatorze do niego

Kreator pisze, że zainstaluje wersję 1.0 :wink:

Drugi błąd, podczas sprawdzania nazwy pliku wrzuconego do katalogu, brane są pod uwagę wielkości liter

czyli jak ktos wgrywa plik i ma zdjecie.Jpg zdjecie.jPg, zdjęcie.jpG, zdjęcie … zdjęcie.JPG to nie zostanie skojarzone z regułą .jpg

  • mógłbys to dopisać, ToLower :wink:

bo troche bez sensu robic 8 różnych wpisów dla tego samego w sumie.

Pozdrawiam

Wybaczcie, że tak długo milczałem, ale byłem bardzo zajęty udawaniem, że piszę pracę inżynierską :wink:

Specjalnie dla Ciebie w nowej wersji jest przycisk “Przetwórz”, który umożliwia przeniesienie już istniejących plików. (To zamiast piwa ;))

Dzięki za zwrócenie na to uwagi, już poprawione.

Sądzę, że to kwestia SO. Windows w trakcie kopiowania/przenoszenia pliku blokuje go sobie tylko do zapisu i nie pozwala nikomu ani niczemu innemu czytać (nawet sobie ;)). Natomiast w Linuksie czy to na ext3, czy to na NTFS kopiować/przenosić pliki można jednocześnie. Niby fajny bajer, ale prowadzenie na raz kilku operacji trwa dłużej, niż wykonywanie ich po kolei.

No tak, ale w ogóle to, że program wymaga do działania SO jest wadą, lepiej byłoby bez :wink:

Ja nie widzę nic złego, że mój program wymaga frameworka do działania. Za to mógł szybko powstać i jest dobrze zrośnięty z systemem operacyjnym. Jeśli ktoś nie chce sobie doinstalować frameworka - jego sprawa. Inna rzecz, że w nowszych systemach na szczęście .NET już jest.

Wiesz - tworzę programy dla użytkowników Windows, bo wychodzę z założenia, że linuksowcy sami sobie potrafią zrobić, co im potrzeba.

W nowszej wersji dodałem ich obsługę, ale bez zachowywania struktury katalogów. Tzn. pliki z wszystkich podkatalogów katalogu monitorowanego trafiają do głównego katalogu docelowego.

W przypadku takiego skryptu jak Twój należałoby użyć rekurencji, ja natomiast mam ułatwione zadanie. Korzystam z takiego magicznego komponentu FileSystemWatcher, który służy do monitorowania katalogu. W momencie, gdy jest np. tworzony plik wywołuje zdarzenie, które ja oprogramowałem. Aby monitorować także podkatalogi wystarczy ustawić IncludeSubdirectiories na true :slight_smile:

Plusem tego jest, że praktycznie nie zużywa zasobów. W tym przypadku może to nie ma znaczenia, ale gdyby robić to ręcznie, wywołując rekurencyjnie funkcje, dla jakiejś bardziej skomplikowanej struktury katalogów i wielu plików, mogłoby to nieźle zamulić procesor.

No ja je po prostu pomijam. A co innego można z nimi zrobić? ;>

No to już powinno być określone w specyfikacji funkcjonalnej tworzonej przez zamawiającego oprogramowanie :slight_smile:

Działa.

U mnie się przerywa, po prostu zostaje gdzieś nie do końca przeniesiony plik.

Nie jest to zbyt eleganckie, ale żeby móc ładnie anulować i usunąć ewentualne pozostałości trzeba by dodać sporo kodu, pewno nawet wątki, lub napisać własne metody przenoszące, a tego mi się chwilowo nie chce robić.

Ja wychodzę z założenia, że od takich rzeczy jest system operacyjny :slight_smile:

Nowa wersja: http://www.somekind.pl/_upload/AutoFileMoveSetup.2.2.exe

Tyle, że w moim skrypcie za bardzo nie ma czego wywoływać rekurencyjnie :slight_smile: Owszem, najpierw rekurencyjnie bym zebrał wszystkie nazwy plików w podkatalogach za pomocą Glob::find_all_subdirs_recursively - czyli +1 linijka kodu. Ewentualnie bardziej “ręcznie” za pomocą File::Find. Jak już pisałem w Perlu skrypcik pisałbym dla siebie, a gdybym musiał coś takiego napisać pewnie użyłbym GIO i GFileMonitor - równie magiczną klasę.

Od kiedy klient wie czego chce? :smiley:

Przypomniało mi się:

Nie mam już raczej nic do dodania w tym temacie, raczej nie jestem targetem twojego programu. Dzięki za pokazanie kodu, to chyba nie było takie straszne? :slight_smile:

Dobrze wiedzieć :slight_smile:

Zastanawia mnie tylko jak to działa tak od wewnątrz, wiesz może?

Nie wie, dlatego trzeba go dopytywać. Dopóki się nie wypowie, to nic nie robię :slight_smile:

No nie ma co udawać, nie jesteś. Chyba, że zmienisz środowisko pracy :slight_smile:

Co prawda wzrosło mi ciśnienie i cholesterol, ale chyba przeżyję :wink:

WOW! :o Totalnie ulepszona wersja!

Przetestowałem przycisk “Przetwórz” (czyli skopiowałem plik BAT do folderu testowego przed uruchomieniem programu). DZIAŁA! Po kliknięciu przycisku “Przetwórz” plik testowy BAT przenosi się z foldera testowego do folderu Moje pliki batowe!

Brakuje jeszcze kilka poprawek:

  • Żeby po dwukrotnym kliknięciu ikonki w trayu pokazywało się okno konfiguracyjne programu

  • No i tak jak Zulowski napisał:

Możesz w instalatorze zmienić, że zainstaluje wersję 2.3 (bo nie można niby instalatora poprawić, więc żeby instalator do wersji 2.3 był poprawiony)

  • Żeby przy starcie systemu program się uruchamiał, ale w inny sposób (bo ja wiem, że się dodaje do autostartu), żeby po uruchomieniu nie pokazywało się okienko konfiguracyjne programu

Mam nadzieję, że te poprawki uwzględnisz w wersji 2.3 :smiley:

PS. Folder Moje pliki batowe to też przykład :slight_smile:

EDIT

Co wy tak długo milczycie ?? :o

Ja już 3-4 dni czekam na jakiegoś posta, a tu nic !!

Tego można się było spodziewać po studencie, zrobi wszystko by zachować piwo dla siebie:P

dzięki :slight_smile: