Jaki jest najprostszy sposób blokowania wątku, dopóki plik nie zostanie odblokowany i będzie można go odczytać i zmienić jego nazwę? Na przykład, czy gdzieś w .NET Framework istnieje WaitOnFile ()?
Mam usługę, która używa FileSystemWatcher do wyszukiwania plików, które mają zostać przesłane do witryny FTP, ale zdarzenie utworzone w pliku jest wyzwalane, zanim inny proces zakończy zapisywanie pliku.
Idealne rozwiązanie miałoby limit czasu, aby wątek nie zawieszał się na zawsze, zanim się poddaje.
Edycja: po wypróbowaniu niektórych z poniższych rozwiązań skończyło się na zmianie systemu tak, aby wszystkie pliki były zapisywane Path.GetTempFileName()
, a następnie przeprowadziłem File.Move()
do ostatecznej lokalizacji. Zaraz po uruchomieniu FileSystemWatcher
zdarzenia plik był już kompletny.
Odpowiedzi:
Oto odpowiedź, której udzieliłem na powiązane pytanie :
źródło
Zaczynając od odpowiedzi Erica, dodałem kilka ulepszeń, aby kod był znacznie bardziej zwarty i wielokrotnego użytku. Mam nadzieję, że to przydatne.
źródło
using
ustawić wartość null, po prostu sprawdź, czy wusing
bloku nie ma wartości null .fs
być zerowa wcatch
bloku? JeśliFileStream
konstruktor zgłosi, zmiennej nie zostanie przypisana wartość, a wewnątrz elementu nie ma nic innego,try
co mogłoby zgłosićIOException
. Wydaje mi się, że powinno to być w porządkureturn new FileStream(...)
.Oto ogólny kod, który to robi, niezależnie od samej operacji na plikach. Oto przykład, jak go używać:
lub
Możesz również zdefiniować liczbę ponownych prób i czas oczekiwania między kolejnymi próbami.
UWAGA: Niestety, podstawowy błąd Win32 (ERROR_SHARING_VIOLATION) nie jest ujawniany w .NET, więc dodałem małą funkcję hackowania (
IsSharingViolation
) opartą na mechanizmach odbicia, aby to sprawdzić.źródło
SharingViolationException
. W rzeczywistości nadal mogą, w sposób zgodny z poprzednimi wersjami, o ile pochodzi zIOException
. I naprawdę, naprawdę powinni.Starting with the .NET Framework 4.5, the HResult property's setter is protected, whereas its getter is public. In previous versions of the .NET Framework, both getter and setter are protected.
Zorganizowałem razem zajęcia pomocnicze na tego typu rzeczy. Będzie działać, jeśli masz kontrolę nad wszystkim, co ma dostęp do pliku. Jeśli spodziewasz się sporu z wielu innych rzeczy, to jest to bezwartościowe.
Działa przy użyciu nazwanego muteksu. Ci, którzy chcą uzyskać dostęp do pliku, próbują przejąć kontrolę nad nazwanym muteksem, który ma wspólną nazwę pliku (z '\' zamienionymi na \ '). Możesz użyć Open (), która będzie się zatrzymywać, dopóki mutex nie będzie dostępny, lub możesz użyć TryOpen (TimeSpan), który próbuje uzyskać muteks na określony czas i zwraca false, jeśli nie może uzyskać w określonym przedziale czasu. Najprawdopodobniej powinno to być używane wewnątrz bloku using, aby zapewnić prawidłowe zwolnienie blokad, a strumień (jeśli jest otwarty) zostanie prawidłowo usunięty, gdy ten obiekt zostanie usunięty.
Zrobiłem szybki test z ~ 20 rzeczami, aby wykonać różne odczyty / zapisy pliku i nie zauważyłem żadnych uszkodzeń. Oczywiście nie jest bardzo zaawansowany, ale powinien działać w większości prostych przypadków.
źródło
W przypadku tej konkretnej aplikacji bezpośrednia obserwacja pliku nieuchronnie prowadzi do trudnego do wyśledzenia błędu, zwłaszcza gdy zwiększa się rozmiar pliku. Oto dwie różne strategie, które będą działać.
Powodzenia!
źródło
Jedną z technik, których użyłem kiedyś, było napisanie własnej funkcji. Zasadniczo złap wyjątek i spróbuj ponownie, używając timera, który możesz odpalić przez określony czas. Jeśli istnieje lepszy sposób, udostępnij.
źródło
Z MSDN :
Twój FileSystemWatcher może zostać zmodyfikowany, aby nie wykonywał odczytu / zmiany nazwy podczas zdarzenia „OnCreated”, ale raczej:
źródło
W większości przypadków proste podejście, takie jak sugerowane przez @harpo, będzie działać. Możesz opracować bardziej wyrafinowany kod, stosując następujące podejście:
źródło
Reklama do przesłania pliku wyzwalającego proces SameNameASTrasferedFile.trg, który jest tworzony po zakończeniu transmisji pliku.
Następnie skonfiguruj FileSystemWatcher, który będzie uruchamiał zdarzenie tylko w pliku * .trg.
źródło
Nie wiem, czego używasz do określenia stanu blokady pliku, ale coś takiego powinno wystarczyć.
źródło
Możliwym rozwiązaniem byłoby połączenie obserwatora systemu plików z pewnym odpytywaniem,
otrzymuj powiadomienie o każdej zmianie w pliku, a po otrzymaniu powiadomienia sprawdź, czy jest zablokowane zgodnie z aktualnie zaakceptowaną odpowiedzią: https://stackoverflow.com/a/50800/6754146 Kod do otwarcia strumienia pliku jest kopiowany z odpowiedzi i lekko zmodyfikowane:
W ten sposób możesz sprawdzić, czy plik jest zablokowany i otrzymać powiadomienie po jego zamknięciu przez określone wywołanie zwrotne, w ten sposób unikniesz zbyt agresywnego odpytywania i wykonujesz pracę tylko wtedy, gdy może być faktycznie zamknięty
źródło
Robię to tak samo, jak Gulzar, po prostu próbuj dalej z pętlą.
W rzeczywistości nawet nie zawracam sobie głowy obserwatorem systemu plików. Sondowanie dysku sieciowego w poszukiwaniu nowych plików raz na minutę jest tanie.
źródło
Po prostu użyj zdarzenia Changed z NotifyFilter NotifyFilters.LastWrite :
źródło
Napotkałem podobny problem podczas dodawania załącznika Outlook. „Korzystanie” uratowało dzień.
źródło
Co powiesz na to jako opcję:
Oczywiście, jeśli rozmiar pliku jest wstępnie przydzielony do tworzenia, otrzymasz fałszywie dodatni wynik.
źródło