CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Jak sprawdzić czy w katalogu pojawił się nowy plik.

Jak sprawdzić czy w katalogu pojawił się nowy plik.

dział ogólny

Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » niedziela, 4 września 2016, 16:55

Wiem jak wyliczyć wszystkie pliki w katalogu, ale zastanawia mnie czy jest sposób na sprawdzenie, czy w takim już wyliczonym katalogu pojawił się nowy plik bez konieczności ponownego wyliczania wszystkich plików. Prosiłbym o trochę kodu, bo z teorią to u mnie jest różnie.
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez polymorphism » niedziela, 4 września 2016, 18:11

C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » niedziela, 16 października 2016, 18:43

Ten kod z MSDN był za długi. Poradziłem sobie inaczej. Fragment kodu:

KOD cpp:     UKRYJ  
void __fastcall TForm1::SetWatchPath(String Value)
{
    if (FWatchPath != Value)
    {
        FWatchPath = Value;
        if (FChangeHandle != INVALID_HANDLE_VALUE)
                        FindCloseChangeNotification(FChangeHandle);


                DWORD dwFlags = FILE_NOTIFY_CHANGE_FILE_NAME |
                                        FILE_NOTIFY_CHANGE_DIR_NAME |
                        FILE_NOTIFY_CHANGE_ATTRIBUTES;
                FChangeHandle = INVALID_HANDLE_VALUE;
        FChangeHandle = FindFirstChangeNotification( Value.c_str(), false, dwFlags);
    }
}


Kod działa. Powiadamia o zmianach w zadanym katalogu, ale nie wiem jak pobrać ścieżkę do pliku, który został jako ostatni dodany do tegoż katalogu. Nie mam pomysłu.
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » niedziela, 16 października 2016, 20:49

Dodałem taki kod:

KOD cpp:     UKRYJ  
        int nCounter;
        FILE_NOTIFY_INFORMATION strFileNotifyInfo[1024];

        DWORD dwBytesReturned = 0;
        HANDLE hDir = CreateFile(
        Value.c_str(),
    FILE_LIST_DIRECTORY,
    FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS,
    NULL
        );
        if( ReadDirectoryChangesW( hDir, (LPVOID)&strFileNotifyInfo,
                                                           sizeof(strFileNotifyInfo), FALSE,
                                                           FILE_NOTIFY_CHANGE_FILE_NAME,
                                                           &dwBytesReturned, NULL, NULL) )
          {
                sFile = strFileNotifyInfo[0].FileName;
          }
        }


Zwraca mi nazwę pliku, ale tylko pierwszego jaki dodam do katalogu. gdy dodaję kolejne pliki to zawsze zwraca mi naz tylko pierwszego dodanego pliku, a nie tego kolejnego. Ponadto na końcu nazwy pliku dodaje mi coś takiego t\Wind, czyli np. readme.txtt\Wind. Poza tym po uruchomieniu czuwania program się jakby zawiesza dopóki nie zajdą zmiany w zadanym katalogu. Rozumiem to w ten sposób: po pierwszym wyszukaniu pliku funkcja ReadDirectoryChangesW przestaje działać. Cały kod funkcji wygląda teraz tak:

KOD cpp:     UKRYJ  
void __fastcall TFom1::SetWatchPath(String Value)
{
    if (FWatchPath != Value)
    {
                FWatchPath = Value;
        if (FChangeHandle != INVALID_HANDLE_VALUE)
                        FindCloseChangeNotification(FChangeHandle);


                DWORD dwFlags = FILE_NOTIFY_CHANGE_FILE_NAME |
                                        FILE_NOTIFY_CHANGE_DIR_NAME |
                        FILE_NOTIFY_CHANGE_ATTRIBUTES;
                FChangeHandle = INVALID_HANDLE_VALUE;
        FChangeHandle = FindFirstChangeNotification( Value.c_str(),
                                                                                                        false, dwFlags);

        int nCounter;
        FILE_NOTIFY_INFORMATION strFileNotifyInfo[1024];

        DWORD dwBytesReturned = 0;
        HANDLE hDir = CreateFile(
        Value.c_str(),
    FILE_LIST_DIRECTORY,
    FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS,
    NULL
        );
        if( ReadDirectoryChangesW( hDir, (LPVOID)&strFileNotifyInfo,
                                                           sizeof(strFileNotifyInfo), FALSE,
                                                           FILE_NOTIFY_CHANGE_FILE_NAME,
                                                           &dwBytesReturned, NULL, NULL) )
          {
                sFile = strFileNotifyInfo[0].FileName;
          }
        }
}
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez polymorphism » poniedziałek, 17 października 2016, 12:14

Jakoś tak to powinno być:
KOD cpp:     UKRYJ  
// wywołanie ReadDirectoryChangesW

 FILE_NOTIFY_INFORMATION *p = strFileNotifyInfo;

 vector<wstring> fileNames; // <--- tu będą nazwy zwrócone przez ReadDirectoryChangesW

while(1)
{
        fileNames.emplace_back(p->FileName, p->FileNameLength / 2);
        if(p->NextEntryOffset == 0) break;

        p =(FILE_NOTIFY_INFORMATION*) (((BYTE*) p) + p->NextEntryOffset);
}
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » poniedziałek, 17 października 2016, 16:15

Dziękuję. Sprawdzanie czy zaszły zmiany w zadanym katalogu przerzuciłem do nowej klasy zbudowanej w oparciu o klasę TThread i teraz sprawdza mi to w oddzielnym wątku. Gdy zmiany zostaną wykryte sprawdzam wtedy jakie pliki się tam znalazły. Szukałem jakiegoś sposobu by mi podał tylko ostatni dodany do katalogu plik, ale nic mi z tym nie wychodzi, więc pozostaję przy ReadDirectoryChangesW i tym co mi podałeś.
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » poniedziałek, 17 października 2016, 18:21

Miałbym pewien pomysł, ale nie bardzo wiem jak go zrealizować. O ile dobrze zrozumiałem to funkcja ReadDirectoryChangesW tylko za pierwszym razem wykrywa ostatnio dodany plik, później wypełnia strukturę FILE_NOTIFY_INFORMATION kolejnymi plikami, więc na pierwszej pozycji struktury zawsze jest ten pierwszy-ostatni plik. Czy można by tą funkcją jakoś resetować, żeby za każdym wywołaniem zawsze podawała ten ostatnio dodany plik?
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez polymorphism » poniedziałek, 17 października 2016, 19:50

W moim kodzie był drobny błąd przy dodawaniu do vectora. Popraw linię:
KOD cpp:     UKRYJ  
fileNames.emplace_back(p->FileName, p->FileNameLength);

na
KOD cpp:     UKRYJ  
fileNames.emplace_back(p->FileName, p->FileNameLength / 2);


Teraz wszystko powinno działać jak trzeba.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » piątek, 21 października 2016, 18:47

Niestety otrzymuję komunikat błędu:


[BCC32 Error] DirMonitorThread.cpp(62): E2316 'emplace_back' is not a member of 'vector<wstring,allocator<wstring> >'

Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » piątek, 21 października 2016, 20:01

No trudno. Nie potrafię tego rozgryźć. O ile sprawdzanie czy do katalogu został dodany jakiś plik nie sprawia mi problemu, o tyle pobranie nazwy ostatnio dodanego pliku wydaje się niemożliwe. No nic. Dzięki za dobrze chęci.
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez polymorphism » piątek, 21 października 2016, 20:11

Łoo, Panie! W czym Ty to piszesz? emplace_back jest od 2011 roku w standardzie. Lepiej zmień kompilator na nowszy.

Zamiast emplace_back możesz użyć push_back:
KOD cpp:     UKRYJ  
fileNames.push_back( wstring(p->FileName, p->FileNameLength / 2) );

Mniej efektywne rozwiązanie, ale w tym przypadku to bez znaczenia...


(...) o tyle pobranie nazwy ostatnio dodanego pliku wydaje się niemożliwe.

Nie wiem, z czym masz problem, ale u mnie wszystko jest jak trzeba. Listuje wszystkie pliki dodane do/usunięte z katalogu.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » sobota, 22 października 2016, 09:17

W C++Builder XE. Funkcja push_back występuje, ale z tych kawałków kodu, które podajesz nie da się nic sklecić. To tak jakbym składał klocki, które do siebie nie pasują. Gdzie dokładnie jest nazwa ostatniego pliku i jak ją przepisać do zmiennej UnicodeString?
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez polymorphism » sobota, 22 października 2016, 11:42

I wszystko jasne. XE jest 2010 roku. Radzę zmienić kompilator, bo aktualny standard jest z 2014, a szykuje się nowy w 2017. Twoje środowisko zapewne jedzie na standardzie z 2003 roku, a od tamtego czasu sporo się zmieniło, i coraz częściej będziesz miał problemy z kompilacją nawet banalnych kodów.

(...) ale z tych kawałków kodu, które podajesz nie da się nic sklecić.

Nie "nie da się nic sklecić", tylko Ty prawdopodobnie nie bardzo wiesz, co ten kod robi. Ta pętla ładuje do vectora wszystkie nazwy plików zwrócone przez ReadDirectoryChangesW. Co nie oznacza, że jeśli do katalogu zostanie dodanych 100 plików, to w vectorze po jednym wywołaniu będzie także 100 nazw. To tak nie działa. ReadDirectoryChangesW zwróci Ci tyle nazw, ile będzie w danej chwili w wewnętrznym buforze.

Gdzie dokładnie jest nazwa ostatniego pliku

W ostatnim elemencie vectora.

i jak ją przepisać do zmiennej UnicodeString?

Użyj metody wstring::c_str. Może można by było od razu dać vector<UnicodeString>, gdyby UnicodeString miał konstruktor taki jak ten z wstringa. Nie wiem, albo ślepy jestem, albo w tej durnej dokumentacji nie ma opisu konstruktorów dla tej klasy ;\ Musisz sam sobie to sprawdzić. Zwykłe przypisanie FILE_NOTIFY_INFORMATION::FileName nie wchodzi w grę.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez Norbit » sobota, 22 października 2016, 12:08

O tym, że wrzuca do wektora wszystkie pliki w katalogu to oczywiście wiedziałam. Liczyłem tylko, że może coś tam tak poustawiałeś, że otrzymam tylko ostatni plik. Czy należy rozumieć to w ten sposób, że do vector na ostatniej pozycji zawsze znajduje się ostatni dodany do katalogu plik? Czy można coś poradzić na blokowanie programu przez funkcję ReadDirectoryChangesW?
Avatar użytkownika
Norbit
Bladawiec
Bladawiec
 
Posty: 33
Dołączył(a): wtorek, 15 lipca 2008, 22:43
Podziękował : 1
Otrzymał podziękowań: 1
    Windows 7Firefox

Re: Jak sprawdzić czy w katalogu pojawił się nowy plik.

Nowy postprzez polymorphism » sobota, 22 października 2016, 12:38

Ad. 1. Ostatni zwrócony przez ReadDirectoryChangesW. U mnie przy dodaniu 6 plików trzeba było 2 lub 3 wywołań funkcji, żeby wyciągnąć wszystkie zmiany.
Ad. 2. Opcje są dwie: użyć wątka lub wywoływać ReadDirectoryChangesW w trybie asynchronicznym.

--- dopisane ---

Tak myślę sobie, że w przypadku wątka też skłaniałbym się ku opcji asynchronicznej, bo przecież nie da się go zamknąć "po bożemu" jeśli ReadDirectoryChangesW będzie czekać na zdarzenie. Trzeba by brutalnie ubijać, a to w C++ jest niedobre.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows 7Firefox

Następna strona

  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 8 gości

cron