IOException: proces nie może uzyskać dostępu do pliku „ścieżka pliku”, ponieważ jest używany przez inny proces

172

Mam trochę kodu i kiedy się wykonuje, rzuca IOException, mówiąc to

Proces nie może uzyskać dostępu do pliku „nazwa_pliku”, ponieważ jest używany przez inny proces

Co to oznacza i co mogę z tym zrobić?

Adriano Repetti
źródło
1
Zobacz to pytanie, aby dowiedzieć się, jak znaleźć inny proces korzystający z pliku.
stomia

Odpowiedzi:

274

Jaka jest przyczyna?

Komunikat o błędzie jest dość jasny: próbujesz uzyskać dostęp do pliku i nie jest on dostępny, ponieważ inny proces (lub nawet ten sam proces) coś z nim robi (i nie pozwala na żadne udostępnianie).

Debugowanie

Może to być dość łatwe do rozwiązania (lub dość trudne do zrozumienia), w zależności od konkretnego scenariusza. Zobaczmy trochę.

Twój proces jest jedynym, który ma dostęp do tego pliku.
Masz pewność, że drugi proces to Twój własny proces. Jeśli wiesz, że otwierasz ten plik w innej części programu, to przede wszystkim musisz sprawdzić, czy po każdym użyciu poprawnie zamykasz uchwyt pliku. Oto przykład kodu z tym błędem:

var stream = new FileStream(path, FileAccess.Read);
var reader = new StreamReader(stream);
// Read data from this file, when I'm done I don't need it any more
File.Delete(path); // IOException: file is in use

Na szczęście FileStreamimplementuje IDisposable, więc łatwo jest opakować cały kod w usinginstrukcję:

using (var stream = File.Open("myfile.txt", FileMode.Open)) {
    // Use stream
}

// Here stream is not accessible and it has been closed (also if
// an exception is thrown and stack unrolled

Ten wzorzec zapewni również, że plik nie zostanie otwarty w przypadku wyjątków (może to być powód, dla którego plik jest używany: coś poszło nie tak i nikt go nie zamknął; zobacz przykład w tym poście ).

Jeśli wszystko wydaje się w porządku (jesteś pewien, że zawsze zamykasz każdy otwierany plik, nawet w przypadku wyjątków) i masz wiele działających wątków, masz dwie opcje: przerobić kod w celu serializacji dostępu do plików (nie zawsze jest to wykonalne i nie zawsze potrzebne) lub zastosuj wzorzec ponawiania . To dość powszechny wzorzec dla operacji I / O: próbujesz coś zrobić, aw przypadku błędu czekasz i próbujesz ponownie (czy zadałeś sobie pytanie, dlaczego na przykład powłoka systemu Windows potrzebuje trochę czasu, aby poinformować Cię, że plik jest używany i nie można go usunąć?). W C # jest to dość łatwe do zaimplementowania (zobacz także lepsze przykłady dotyczące operacji we / wy dysków , sieci i dostępu do bazy danych ).

private const int NumberOfRetries = 3;
private const int DelayOnRetry = 1000;

for (int i=1; i <= NumberOfRetries; ++i) {
    try {
        // Do stuff with file
        break; // When done we can break loop
    }
    catch (IOException e) when (i <= NumberOfRetries) {
        // You may check error code to filter some exceptions, not every error
        // can be recovered.
        Thread.Sleep(DelayOnRetry);
    }
}

Zwróć uwagę na typowy błąd, który bardzo często widzimy w StackOverflow:

var stream = File.Open(path, FileOpen.Read);
var content = File.ReadAllText(path);

W tym przypadku ReadAllText()nie powiedzie się, ponieważ plik jest używany ( File.Open()w linii przed). Wcześniejsze otwarcie pliku jest nie tylko niepotrzebne, ale także złe. To samo odnosi się do wszystkich Filefunkcji, które nie zwracają się uchwyt do pliku, nad którym pracujesz z: File.ReadAllText(), File.WriteAllText(), File.ReadAllLines(), File.WriteAllLines()i innych (takich File.AppendAllXyz()funkcji) będzie wszystko otwarte i zamknij plik przez siebie.

Twój proces nie jest jedynym, który ma dostęp do tego pliku.
Jeśli Twój proces nie jest jedynym, który ma dostęp do tego pliku, interakcja może być trudniejsza. Wzór ponawiania pomoże (jeśli plik nie powinien być otwarty przez kogoś innego, ale to jest, to trzeba podobnego narzędzia Process Explorer, aby sprawdzić , kto robi to, co ).

Sposoby uniknięcia

W stosownych przypadkach zawsze używaj instrukcji using do otwierania plików. Jak wspomniano w poprzednim akapicie, pomoże ci to aktywnie uniknąć wielu typowych błędów (zobacz ten post, aby zobaczyć przykład, jak go nie używać ).

Jeśli to możliwe, spróbuj zdecydować, kto jest właścicielem dostępu do określonego pliku i scentralizuj dostęp za pomocą kilku dobrze znanych metod. Jeśli na przykład masz plik danych, w którym program czyta i zapisuje, to cały kod I / O powinien być umieszczony w jednej klasie. Ułatwi to debugowanie (ponieważ zawsze możesz umieścić tam punkt przerwania i zobaczyć, kto robi co), a także będzie to punkt synchronizacji (jeśli jest to wymagane) dla wielokrotnego dostępu.

Nie zapominaj, że operacje we / wy mogą zawsze kończyć się niepowodzeniem, typowy przykład jest następujący:

if (File.Exists(path))
    File.Delete(path);

Jeśli ktoś usunie plik po, File.Exists()ale wcześniej File.Delete(), wyrzuci on IOExceptionmiejsce, w którym możesz niesłusznie czuć się bezpiecznie.

Jeśli to możliwe, zastosuj wzorzec ponawiania , a jeśli używasz FileSystemWatcher, rozważ odroczenie akcji (ponieważ otrzymasz powiadomienie, ale aplikacja może nadal pracować wyłącznie z tym plikiem).

Scenariusze zaawansowane
Nie zawsze jest to takie proste, więc może być konieczne udostępnienie dostępu komuś innemu. Jeśli na przykład czytasz od początku i piszesz do końca, masz co najmniej dwie możliwości.

1) udostępniać to samo FileStreamz odpowiednimi funkcjami synchronizacji (ponieważ nie jest bezpieczny wątkowo ). Zobacz przykład tego i tego postu.

2) użyj FileSharewyliczania, aby poinstruować system operacyjny, aby zezwalał innym procesom (lub innym częściom twojego własnego procesu) na jednoczesny dostęp do tego samego pliku.

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}

W tym przykładzie pokazałem, jak otworzyć plik do zapisu i udostępnić do czytania; należy pamiętać, że podczas odczytywania i zapisywania nakładania się, skutkuje to niezdefiniowanymi lub nieprawidłowymi danymi. Jest to sytuacja, z którą trzeba sobie poradzić podczas czytania. Należy również pamiętać, że nie zapewnia to dostępu do streamwątku bezpiecznego, więc ten obiekt nie może być udostępniany wielu wątkom, chyba że dostęp jest w jakiś sposób zsynchronizowany (zobacz poprzednie linki). Dostępne są inne opcje udostępniania, które otwierają bardziej złożone scenariusze. Więcej informacji można znaleźć w witrynie MSDN .

Ogólnie N procesów może czytać z tego samego pliku razem, ale tylko jeden powinien pisać, w kontrolowanym scenariuszu możesz nawet włączyć współbieżne zapisy, ale nie można tego uogólnić w kilku akapitach tekstu w tej odpowiedzi.

Czy można odblokować plik używany przez inny proces? Nie zawsze jest to bezpieczne i nie jest takie łatwe, ale tak, jest to możliwe .

Adriano Repetti
źródło
Nie wiem, co jest nie tak z moim kodem, używam bloków, ale nadal pojawia się błąd informujący, że plik jest używany, gdy próbuję go usunąć.
Jamshaid Kamran
Nie, właściwie mam kontrolkę timera, która to robi, obok timera, jeśli ponownie wywołam tę funkcję, zgłosi wyjątek. w zasadzie odszyfrowuję plik do innego pliku tekstowego, a następnie usuwam nowo utworzony plik, który zgłasza wyjątek przy usuwaniu!
Jamshaid Kamran
3
@ جمشیدکامران Po co tworzyć plik z zawartością zawartą w kodzie, a następnie go usuwać? W takim razie wydaje się dziwne tworzenie pliku w pierwszej kolejności. Ponieważ nie wysłałeś kodu, nie wiemy, co robisz. Ale kiedy tworzysz swój plik, jeśli to robisz File.Create(path), powinieneś dodać .Close()na końcu tego, zanim napiszesz do niego. Oprócz usinginstrukcji dotyczących zapisywania plików, a następnie usuwania po nich, są takie pułapki . W swoim pytaniu powinieneś zamieścić kod dotyczący sposobu tworzenia i usuwania pliku. Ale prawdopodobnie wpisuje się w coś wspomnianego powyżej.
vapcguy
Mój kod używa, Directory.SetCreationTimeUTC()ale kończy się niepowodzeniem, gdy Eksplorator plików jest otwarty, twierdząc, że katalog jest używany przez inny proces. Jak mam sobie z tym poradzić?
Kyle Delaney
1
@KyleDelaney Powiedziałbym, że musisz poczekać, aż folder zostanie zamknięty, jeśli nie jest to kilka sekund, wszystko szybko się skomplikuje (zachowaj kolejkę w tle z oczekującymi operacjami? Obserwator systemu plików? Sondowanie?) Możesz chcieć
zadaj
29

Korzystanie z FileShare rozwiązało mój problem z otwieraniem pliku, nawet jeśli jest otwierany przez inny proces.

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
Muhammad Umar
źródło
9

Wystąpił problem podczas przesyłania obrazu, nie można go usunąć i znalazłem rozwiązanie. gl hf

//C# .NET
var image = Image.FromFile(filePath);

image.Dispose(); // this removes all resources

//later...

File.Delete(filePath); //now works
Hudson
źródło
2
Jeśli usuwasz plik, musisz najpierw usunąć obiekt obrazu.
shazia
1
Fajnie, szukałem tego rozwiązania. Miałem też problem z funkcją Image.FromFile.
potomek
1
@thescion :) np
Hudson
1
To zadziałało znakomicie i rozwiązało mój dokładny problem. Chciałem przetworzyć folder plików Tiff, przekonwertować je na strumienie bajt [] i wysłać do usługi, a następnie przenieść folder plików Tiff do folderu archiwum „Przetworzone”. Image.FromFile nakłada blokadę na plik Tiff i nie zwalnia go w odpowiednim czasie, więc kiedy poszedłem przenieść pliki Tiff i zawierający folder, otrzymywałem komunikat o błędzie „używany przez inny proces”, ponieważ blokady były nadal w miejscu. Wykonanie .Release zaraz po pobraniu bajtów pliku Tiff całkowicie rozwiązało ten problem z zablokowanym plikiem.
Deweloper63
4

Otrzymałem ten błąd, ponieważ robiłem File.Move do ścieżki pliku bez nazwy pliku, muszę określić pełną ścieżkę w miejscu docelowym.

miłość na żywo
źródło
I to nie tylko bez nazwy pliku. Nieprawidłowa (docelowa) nazwa pliku - w moim przypadku „... \ plik”. - poda ten sam głupi błąd i skieruje cię w złym kierunku na pół dnia!
Nick Westgate
3

Błąd wskazuje, że inny proces próbuje uzyskać dostęp do pliku. Może ty lub ktoś inny otworzył ją, gdy próbujesz do niej napisać. „Czytaj” lub „Kopiuj” zwykle tego nie powoduje, ale pisanie do niego lub wywoływanie usuwania na nim tak.

Jest kilka podstawowych rzeczy, których należy unikać, o czym wspomniały inne odpowiedzi:

  1. W FileStreamoperacjach umieść go w usingbloku z FileShare.ReadWritetrybem dostępu.

    Na przykład:

    using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
    {
    }

    Pamiętaj, że FileAccess.ReadWritenie jest to możliwe, jeśli używasz FileMode.Append.

  2. Natknąłem się na ten problem, gdy używałem strumienia wejściowego do wykonania, File.SaveAsgdy plik był używany. W moim przypadku nie musiałem w ogóle zapisywać go z powrotem w systemie plików, więc skończyło się na tym, że po prostu to usunąłem, ale prawdopodobnie mogłem spróbować utworzyć FileStream w usinginstrukcji z FileAccess.ReadWrite, podobnie jak kod powyżej.

  3. Zapisanie danych jako inny plik i powrót do usunięcia starego, gdy okaże się, że nie jest już używany, a następnie zmiana nazwy pliku, który został pomyślnie zapisany, na nazwę oryginalnego jest opcją. Sposób testowania używanego pliku odbywa się za pomocą

    List<Process> lstProcs = ProcessHandler.WhoIsLocking(file);

    linii w moim kodzie poniżej i można to zrobić w usłudze Windows, w pętli, jeśli masz określony plik, który chcesz regularnie oglądać i usuwać, gdy chcesz go zastąpić. Jeśli nie zawsze masz ten sam plik, można zaktualizować plik tekstowy lub tabelę bazy danych, aby usługa zawsze sprawdzała nazwy plików, a następnie przeprowadza sprawdzenie procesów, a następnie wykonuje zabijanie i usuwanie procesów na nim, jak to opisuję w następnej opcji. Zauważ, że będziesz potrzebować nazwy użytkownika i hasła do konta, które ma uprawnienia administratora na danym komputerze, oczywiście, aby usunąć i zakończyć procesy.

  4. Jeśli nie wiesz, czy plik będzie używany, gdy próbujesz go zapisać, możesz zamknąć wszystkie procesy, które mogą go używać, takie jak Word, jeśli jest to dokument programu Word, przed zapisaniem.

    Jeśli jest lokalny, możesz to zrobić:

    ProcessHandler.localProcessKill("winword.exe");

    Jeśli jest zdalny, możesz to zrobić:

    ProcessHandler.remoteProcessKill(computerName, txtUserName, txtPassword, "winword.exe");

    gdzie txtUserNamejest w postaci DOMAIN\user.

  5. Powiedzmy, że nie znasz nazwy procesu, który blokuje plik. Następnie możesz to zrobić:

    List<Process> lstProcs = new List<Process>();
    lstProcs = ProcessHandler.WhoIsLocking(file);
    
    foreach (Process p in lstProcs)
    {
        if (p.MachineName == ".")
            ProcessHandler.localProcessKill(p.ProcessName);
        else
            ProcessHandler.remoteProcessKill(p.MachineName, txtUserName, txtPassword, p.ProcessName);
    }

    Zauważ, że filemusi to być ścieżka UNC: \\computer\share\yourdoc.docxaby program Processmógł dowiedzieć się, na jakim komputerze się znajduje i p.MachineNamejest ważny.

    Poniżej znajduje się klasa, której używają te funkcje, do której należy dodać odwołanie System.Management. Kod został pierwotnie napisany przez Erica J .:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Management;
    
    namespace MyProject
    {
        public static class ProcessHandler
        {
            [StructLayout(LayoutKind.Sequential)]
            struct RM_UNIQUE_PROCESS
            {
                public int dwProcessId;
                public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
            }
    
            const int RmRebootReasonNone = 0;
            const int CCH_RM_MAX_APP_NAME = 255;
            const int CCH_RM_MAX_SVC_NAME = 63;
    
            enum RM_APP_TYPE
            {
                RmUnknownApp = 0,
                RmMainWindow = 1,
                RmOtherWindow = 2,
                RmService = 3,
                RmExplorer = 4,
                RmConsole = 5,
                RmCritical = 1000
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            struct RM_PROCESS_INFO
            {
                public RM_UNIQUE_PROCESS Process;
    
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
                public string strAppName;
    
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
                public string strServiceShortName;
    
                public RM_APP_TYPE ApplicationType;
                public uint AppStatus;
                public uint TSSessionId;
                [MarshalAs(UnmanagedType.Bool)]
                public bool bRestartable;
            }
    
            [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
            static extern int RmRegisterResources(uint pSessionHandle,
                                                UInt32 nFiles,
                                                string[] rgsFilenames,
                                                UInt32 nApplications,
                                                [In] RM_UNIQUE_PROCESS[] rgApplications,
                                                UInt32 nServices,
                                                string[] rgsServiceNames);
    
            [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
            static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
    
            [DllImport("rstrtmgr.dll")]
            static extern int RmEndSession(uint pSessionHandle);
    
            [DllImport("rstrtmgr.dll")]
            static extern int RmGetList(uint dwSessionHandle,
                                        out uint pnProcInfoNeeded,
                                        ref uint pnProcInfo,
                                        [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
                                        ref uint lpdwRebootReasons);
    
            /// <summary>
            /// Find out what process(es) have a lock on the specified file.
            /// </summary>
            /// <param name="path">Path of the file.</param>
            /// <returns>Processes locking the file</returns>
            /// <remarks>See also:
            /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
            /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
            /// 
            /// </remarks>
            static public List<Process> WhoIsLocking(string path)
            {
                uint handle;
                string key = Guid.NewGuid().ToString();
                List<Process> processes = new List<Process>();
    
                int res = RmStartSession(out handle, 0, key);
                if (res != 0) throw new Exception("Could not begin restart session.  Unable to determine file locker.");
    
                try
                {
                    const int ERROR_MORE_DATA = 234;
                    uint pnProcInfoNeeded = 0,
                        pnProcInfo = 0,
                        lpdwRebootReasons = RmRebootReasonNone;
    
                    string[] resources = new string[] { path }; // Just checking on one resource.
    
                    res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);
    
                    if (res != 0) throw new Exception("Could not register resource.");
    
                    //Note: there's a race condition here -- the first call to RmGetList() returns
                    //      the total number of process. However, when we call RmGetList() again to get
                    //      the actual processes this number may have increased.
                    res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);
    
                    if (res == ERROR_MORE_DATA)
                    {
                        // Create an array to store the process results
                        RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                        pnProcInfo = pnProcInfoNeeded;
    
                        // Get the list
                        res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
                        if (res == 0)
                        {
                            processes = new List<Process>((int)pnProcInfo);
    
                            // Enumerate all of the results and add them to the 
                            // list to be returned
                            for (int i = 0; i < pnProcInfo; i++)
                            {
                                try
                                {
                                    processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                                }
                                // catch the error -- in case the process is no longer running
                                catch (ArgumentException) { }
                            }
                        }
                        else throw new Exception("Could not list processes locking resource.");
                    }
                    else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
                }
                finally
                {
                    RmEndSession(handle);
                }
    
                return processes;
            }
    
            public static void remoteProcessKill(string computerName, string userName, string pword, string processName)
            {
                var connectoptions = new ConnectionOptions();
                connectoptions.Username = userName;
                connectoptions.Password = pword;
    
                ManagementScope scope = new ManagementScope(@"\\" + computerName + @"\root\cimv2", connectoptions);
    
                // WMI query
                var query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");
    
                using (var searcher = new ManagementObjectSearcher(scope, query))
                {
                    foreach (ManagementObject process in searcher.Get()) 
                    {
                        process.InvokeMethod("Terminate", null);
                        process.Dispose();
                    }
                }            
            }
    
            public static void localProcessKill(string processName)
            {
                foreach (Process p in Process.GetProcessesByName(processName))
                {
                    p.Kill();
                }
            }
    
            [DllImport("kernel32.dll")]
            public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);
    
            public const int MOVEFILE_DELAY_UNTIL_REBOOT = 0x4;
    
        }
    }
vapcguy
źródło
2

Jak wskazywały inne odpowiedzi w tym wątku, aby rozwiązać ten błąd, musisz dokładnie sprawdzić kod, aby zrozumieć, gdzie plik jest blokowany.

W moim przypadku wysyłałem plik jako załącznik do wiadomości e-mail przed wykonaniem operacji przenoszenia.

Plik został więc zablokowany na kilka sekund, aż klient SMTP zakończył wysyłanie wiadomości e-mail.

Rozwiązaniem, które zastosowałem, było najpierw przeniesienie pliku, a następnie wysłanie e-maila. To rozwiązało problem.

Innym możliwym rozwiązaniem, jak wskazał wcześniej Hudson, byłoby pozbycie się przedmiotu po użyciu.

public static SendEmail()
{
           MailMessage mMailMessage = new MailMessage();
           //setup other email stuff

            if (File.Exists(attachmentPath))
            {
                Attachment attachment = new Attachment(attachmentPath);
                mMailMessage.Attachments.Add(attachment);
                attachment.Dispose(); //disposing the Attachment object
            }
} 
Abhishek Poojary
źródło
Jeśli plik jest używany File.Move(), nie działa i wyświetla ten sam błąd. Jeśli po prostu dodam plik do wiadomości e-mail, nie sądzę, że wystąpi błąd podczas używania podczas Attachments.Add()operacji, ponieważ jest to tylko operacja kopiowania. Jeśli z jakiegoś powodu tak się stało, możesz skopiować go do katalogu Temp, dołączyć kopię, a następnie usunąć skopiowany plik. Ale nie sądzę, że jeśli OP chce zmodyfikować plik i użyć tego, to tego rodzaju rozwiązanie (którego nie pokazałeś kodu, tylko część załączająca) zadziałałoby. .Dispose()jest zawsze dobrym pomysłem, ale nie ma tu znaczenia, chyba że plik zostanie otwarty we wcześniejszej operacji.
vapcguy
1

Miałem następujący scenariusz, który powodował ten sam błąd:

  • Prześlij pliki na serwer
  • Następnie pozbądź się starych plików po ich przesłaniu

Większość plików miała mały rozmiar, jednak kilka było dużych, więc próba ich usunięcia spowodowała brak dostępu do pliku błąd .

Nie było to łatwe do znalezienia, jednak rozwiązanie było tak proste, jak oczekiwanie „na zakończenie realizacji zadania”:

using (var wc = new WebClient())
{
   var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
   tskResult.Wait(); 
}
przydatne
źródło
-1

Mój poniższy kod rozwiązuje ten problem, ale sugeruję Przede wszystkim musisz zrozumieć, co powoduje ten problem i wypróbować rozwiązanie, które możesz znaleźć, zmieniając kod

Mogę podać inny sposób rozwiązania tego problemu, ale lepszym rozwiązaniem jest sprawdzenie struktury kodowania i próba przeanalizowania, co tak się dzieje, jeśli nie znajdziesz żadnego rozwiązania, możesz przejść z tym kodem poniżej

try{
Start:
///Put your file access code here


}catch (Exception ex)
 {
//by anyway you need to handle this error with below code
   if (ex.Message.StartsWith("The process cannot access the file"))
    {
         //Wait for 5 seconds to free that file and then start execution again
         Thread.Sleep(5000);
         goto Start;
    }
 }
Popiół
źródło
1
Kilka problemów z tym kodem: 1) jeśli musisz zadzwonić GC.*(), prawdopodobnie masz inne problemy z kodem. 2) Wiadomość jest zlokalizowana i krucha , zamiast tego użyj HRESULT. 3) Możesz chcieć spać Task.Delay()(a dziesięć sekund to w wielu przypadkach zbyt wiele). 4) Nie masz warunku wyjścia: ten kod może zawiesić się na zawsze. 5) Na pewno nie potrzebujesz gototutaj. 6) Złapanie Exceptionjest zwykle złym pomysłem, w tym przypadku także dlatego, że ... 6) Jeśli zdarzy się coś innego, to połykasz błąd.
Adriano Repetti
@AdrianoRepetti mój pierwszy komentarz powiedział, że nie używaj tego kodu, spróbuj znaleźć inne rozwiązanie, to będzie ostatnia opcja, a tak czy inaczej, jeśli wystąpi ten błąd, kod zostanie zatrzymany, ale jeśli obsługujesz ten błąd, system będzie czekał na zwolnienie pliku i po tym się uruchomi działa i nie napotykam innych problemów z GC. * podczas korzystania z tego kodu. mam już działający system z tym kodem, więc zamieszczone przeze mnie mogą być pomocne dla kogoś.
Ash
Powiedziałbym, aby nie korzystać z tego kodu nigdy (bo ja z punktów wymienionych powyżej) i nie chciałbym rozważyć tę pracę w systemie prod ale to tylko moja POV. Nie wahaj się!
Adriano Repetti
1) Korzystałem z usługi Windows, gdzie to konsumowałem i korzystałem z GC. * Do tego czasu nie mam z tym żadnego problemu 2) tak HRESULT może być lepszą opcją pod względem standardu kodowania 3) W zależności od sytuacji, którą możesz dać czas, który właśnie edytowałem to do 5 sekund 4) w każdym razie lepiej jest poczekać przez jakiś czas na zwolnienie zasobu zamiast zatrzymać system z błędem 5) tak, zgadzam się z tobą, obsługa wyjątków nie zawsze jest dobrym pomysłem, ale jeśli twój fragment kodu jest mały i wiesz że tutaj mogę obsłużyć wyjątek, to rozwiązanie jest opcją dla Ciebie.
Ash
Zobacz też: docs.microsoft.com/en-us/archive/blogs/ricom/… . JEDYNYM (i podkreślam TYLKO) przypadek, którego musiałem użyć GC.Collect(), dotyczył niektórych obiektów COM.
Adriano Repetti