IOException: Der Prozess kann nicht auf die Datei 'Dateipfad' zugreifen, da sie von einem anderen Prozess verwendet wird

172

Ich habe einen Code und wenn er ausgeführt wird, wirft er einen IOExceptionund sagt das

Der Prozess kann nicht auf die Datei 'Dateiname' zugreifen, da sie von einem anderen Prozess verwendet wird

Was bedeutet das und was kann ich dagegen tun?

Adriano Repetti
quelle
1
In dieser Frage erfahren Sie, wie Sie den anderen Prozess finden, der die Datei verwendet.
Stomy

Antworten:

274

Was ist die Ursache?

Die Fehlermeldung ist ziemlich klar: Sie versuchen, auf eine Datei zuzugreifen, und sie ist nicht zugänglich, weil ein anderer Prozess (oder sogar derselbe Prozess) etwas damit macht (und keine Freigabe zuließ).

Debuggen

Abhängig von Ihrem spezifischen Szenario kann es ziemlich einfach zu lösen (oder ziemlich schwer zu verstehen) sein. Mal sehen.

Ihr Prozess ist der einzige, der auf diese Datei
zugreift. Sie sind sicher, dass der andere Prozess Ihr eigener Prozess ist. Wenn Sie wissen, dass Sie diese Datei in einem anderen Teil Ihres Programms öffnen, müssen Sie zunächst überprüfen, ob Sie das Dateihandle nach jeder Verwendung ordnungsgemäß schließen. Hier ist ein Beispiel für Code mit diesem Fehler:

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

Glücklicherweise FileStreamimplementiert IDisposable, so ist es einfach, Ihren gesamten Code in eine usingAnweisung zu packen :

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

Dieses Muster stellt auch sicher, dass die Datei im Falle von Ausnahmen nicht geöffnet bleibt (dies kann der Grund sein, warum die Datei verwendet wird: Es ist ein Fehler aufgetreten, und niemand hat sie geschlossen; ein Beispiel finden Sie in diesem Beitrag ).

Wenn alles in Ordnung zu sein scheint (Sie sind sicher, dass Sie jede geöffnete Datei auch in Ausnahmefällen immer schließen) und Sie mehrere Arbeitsthreads haben, haben Sie zwei Möglichkeiten: Überarbeiten Sie Ihren Code, um den Dateizugriff zu serialisieren (nicht immer machbar und nicht immer gesucht) oder wenden Sie ein Wiederholungsmuster an . Es ist ein ziemlich häufiges Muster für E / A-Vorgänge: Sie versuchen, etwas zu tun, und im Fehlerfall warten Sie und versuchen es erneut (haben Sie sich gefragt, warum beispielsweise Windows Shell einige Zeit benötigt, um Sie darüber zu informieren, dass eine Datei verwendet wird? und kann nicht gelöscht werden?). In C # ist die Implementierung ziemlich einfach (siehe auch bessere Beispiele für Festplatten-E / A , Netzwerk und Datenbankzugriff ).

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);
    }
}

Bitte beachten Sie einen häufigen Fehler, den wir sehr oft bei StackOverflow sehen:

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

In diesem Fall ReadAllText()schlägt dies fehl, da die Datei verwendet wird ( File.Open()in der vorherigen Zeile). Das vorherige Öffnen der Datei ist nicht nur unnötig, sondern auch falsch. Das gleiche gilt für alle FileFunktionen, die keinen Rückgriff Sie arbeiten mit an der Datei: File.ReadAllText(), File.WriteAllText(), File.ReadAllLines(), File.WriteAllLines()und andere (wie File.AppendAllXyz()Funktionen) werden alle öffnen und schließen Sie die Datei selbst.

Ihr Prozess ist nicht der einzige, der auf diese Datei zugreift.
Wenn Ihr Prozess nicht der einzige ist, der auf diese Datei zugreift, kann die Interaktion schwieriger sein. Ein Wiederholungsmuster hilft (wenn die Datei nicht von jemand anderem geöffnet werden sollte, aber dies ist der Fall, benötigen Sie ein Dienstprogramm wie Process Explorer, um zu überprüfen, wer was tut ).

Möglichkeiten zu vermeiden

Verwenden Sie gegebenenfalls immer using- Anweisungen, um Dateien zu öffnen. Wie im vorherigen Absatz erwähnt, hilft es Ihnen aktiv, viele häufige Fehler zu vermeiden (in diesem Beitrag finden Sie ein Beispiel, wie Sie es nicht verwenden können ).

Versuchen Sie nach Möglichkeit zu entscheiden, wem der Zugriff auf eine bestimmte Datei gehört, und zentralisieren Sie den Zugriff mithilfe einiger bekannter Methoden. Wenn Sie beispielsweise eine Datendatei haben, in der Ihr Programm liest und schreibt, sollten Sie den gesamten E / A-Code in einer einzigen Klasse einschließen. Dies erleichtert das Debuggen (da Sie dort immer einen Haltepunkt setzen und sehen können, wer was tut) und ist ein Synchronisationspunkt (falls erforderlich) für den Mehrfachzugriff.

Vergessen Sie nicht, dass E / A-Vorgänge immer fehlschlagen können. Ein häufiges Beispiel ist Folgendes:

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

Wenn jemand die Datei nach, File.Exists()aber vorher löscht File.Delete(), wird sie IOExceptionan einen Ort geworfen, an dem Sie sich möglicherweise fälschlicherweise sicher fühlen.

Wenden Sie nach Möglichkeit ein Wiederholungsmuster an. Wenn Sie es verwenden FileSystemWatcher, sollten Sie die Aktion verschieben (da Sie benachrichtigt werden, eine Anwendung jedoch möglicherweise weiterhin ausschließlich mit dieser Datei arbeitet).

Erweiterte Szenarien
Es ist nicht immer so einfach, daher müssen Sie möglicherweise den Zugriff für andere Personen freigeben. Wenn Sie beispielsweise von Anfang an lesen und bis zum Ende schreiben, haben Sie mindestens zwei Möglichkeiten.

1) teilen Sie das gleiche FileStreammit den richtigen Synchronisationsfunktionen (weil es nicht threadsicher ist ). Ein Beispiel finden Sie in diesem und diesen Beiträgen.

2) Verwenden Sie die FileShareAufzählung, um das Betriebssystem anzuweisen, anderen Prozessen (oder anderen Teilen Ihres eigenen Prozesses) den gleichzeitigen Zugriff auf dieselbe Datei zu ermöglichen.

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

In diesem Beispiel habe ich gezeigt, wie eine Datei zum Schreiben geöffnet und zum Lesen freigegeben wird. Bitte beachten Sie, dass beim Lesen und Schreiben von Überschneidungen undefinierte oder ungültige Daten entstehen. Es ist eine Situation, die beim Lesen behandelt werden muss. Beachten Sie auch, dass dies keinen Zugriff auf den streamThread sicher macht, sodass dieses Objekt nicht für mehrere Threads freigegeben werden kann, es sei denn, der Zugriff ist irgendwie synchronisiert (siehe vorherige Links). Andere Freigabeoptionen sind verfügbar und eröffnen komplexere Szenarien. Weitere Informationen finden Sie in MSDN .

Im Allgemeinen können N Prozesse alle zusammen aus derselben Datei lesen, aber nur einer sollte schreiben. In einem kontrollierten Szenario können Sie sogar gleichzeitige Schriften aktivieren, dies kann jedoch nicht in wenigen Textabschnitten in dieser Antwort verallgemeinert werden.

Ist es möglich, eine von einem anderen Prozess verwendete Datei zu entsperren ? Es ist nicht immer sicher und nicht so einfach, aber ja, es ist möglich .

Adriano Repetti
quelle
Ich weiß nicht, was mit meinem Code falsch ist. Ich verwende Blöcke, aber es gibt immer noch einen Fehler, der besagt, dass die Datei verwendet wird, wenn ich versuche, sie zu löschen.
Jamshaid Kamran
Nein, eigentlich habe ich neben dem Timer eine Timer-Steuerung, die eine Ausnahme auslöst, wenn ich die Funktion erneut aufrufe. Im Grunde entschlüssele ich eine Datei in eine andere Textdatei, danach lösche ich die neu erstellte Datei, die beim Löschen die Ausnahme auslöst!
Jamshaid Kamran
3
@ جمشیدکامران Warum eine Datei mit Inhalten in Ihrem Code erstellen und dann löschen? Scheint seltsam, die Datei dann überhaupt erst zu erstellen. Da Sie keine Postleitzahl angegeben haben, wissen wir nicht, was Sie tun. Wenn Sie Ihre Datei erstellen File.Create(path), sollten Sie sie .Close()am Ende hinzufügen , bevor Sie darauf schreiben. Es gibt solche Fallstricke, zusätzlich zu den usingAnweisungen zum Schreiben der Dateien und zum anschließenden Löschen. Sie sollten den Code in Ihrer Frage veröffentlichen, wie Sie Ihre Datei erstellen und löschen. Aber wahrscheinlich stimmt mit etwas oben Erwähntem überein.
Vapcguy
Mein Code wird verwendet Directory.SetCreationTimeUTC(), schlägt jedoch fehl, wenn der Datei-Explorer geöffnet ist und behauptet, dass ein anderer Prozess auf das Verzeichnis zugreift. Wie soll ich mit dieser Situation umgehen?
Kyle Delaney
1
@KyleDelaney Ich würde sagen, dass Sie warten müssen, bis der Ordner geschlossen wurde. Wenn es nicht ein paar Sekunden sind, wird alles schnell komplex (eine Hintergrundwarteschlange mit ausstehenden Vorgängen führen? Dateisystem-Watcher? Polling?) Möglicherweise möchten Sie poste eine Frage mit mehr Details für eine Ad-hoc-Antwort
Adriano Repetti
28

Die Verwendung von FileShare hat mein Problem beim Öffnen von Dateien behoben, auch wenn diese von einem anderen Prozess geöffnet wurden.

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
Muhammad Umar
quelle
9

Hatte ein Problem beim Hochladen eines Bildes und konnte es nicht löschen und fand eine Lösung. Viel Glück und Viel Spaß

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

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

//later...

File.Delete(filePath); //now works
Hudson
quelle
2
Wenn Sie eine Datei löschen, müssen Sie zuerst das Bildobjekt entsorgen.
Shazia
1
Schön, ich habe nach dieser Lösung gesucht. Ich hatte auch ein Problem mit der Image.FromFile-Funktion.
Der Spross
1
@thescion :) np
Hudson
1
Das hat bei mir hervorragend funktioniert und mein genaues Problem gelöst. Ich wollte einen Ordner mit Tiff-Dateien verarbeiten, sie in Byte [] -Streams konvertieren und an einen Dienst senden und dann den Ordner mit Tiff-Dateien in einen "verarbeiteten" Archivordner verschieben. Das Image.FromFile setzt eine Sperre für die Tiff-Datei und gibt sie nicht rechtzeitig frei. Wenn ich also die Tiff-Dateien und den enthaltenen Ordner verschiebe, wird der Fehler "Von einem anderen Prozess verwendet" angezeigt, da die Sperren weiterhin bestehen an Ort und Stelle. Durch Ausführen der .Release direkt nach dem Abrufen der Bytes der Tiff-Datei wurde dieses Problem mit gesperrten Dateien vollständig behoben.
Developer63
4

Ich habe diesen Fehler erhalten, weil ich File.Move zu einem Dateipfad ohne Dateinamen ausgeführt habe. Sie müssen den vollständigen Pfad im Ziel angeben.

Live-Liebe
quelle
Und das nicht nur ohne Dateinamen. Ein illegaler (Ziel-) Dateiname - in meinem Fall "... \ Datei". - wird den gleichen dummen Fehler geben und Sie für einen halben Tag in die falsche Richtung weisen!
Nick Westgate
3

Der Fehler zeigt an, dass ein anderer Prozess versucht, auf die Datei zuzugreifen. Vielleicht haben Sie oder jemand anderes es geöffnet, während Sie versuchen, darauf zu schreiben. "Lesen" oder "Kopieren" verursacht dies normalerweise nicht, aber das Schreiben oder Aufrufen von "Löschen" würde dies bewirken.

Es gibt einige grundlegende Dinge, um dies zu vermeiden, wie andere Antworten erwähnt haben:

  1. In FileStreamBetrieb, legen Sie sie in einem usingBlock mit einem FileShare.ReadWriteZugriffsmodus.

    Beispielsweise:

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

    Beachten Sie, dass FileAccess.ReadWritedies bei Verwendung nicht möglich ist FileMode.Append.

  2. Ich bin auf dieses Problem gestoßen, als ich einen Eingabestream verwendet habe, um zu tun, File.SaveAswann die Datei verwendet wurde. In meinem Fall musste ich es eigentlich gar nicht im Dateisystem speichern, also habe ich es letztendlich nur entfernt, aber ich hätte wahrscheinlich versuchen können, einen FileStream in einer usingAnweisung mit zu erstellen FileAccess.ReadWrite, ähnlich wie der Code über.

  3. Speichern Sie Ihre Daten als eine andere Datei und löschen Sie die alte Datei, wenn festgestellt wird, dass sie nicht mehr verwendet wird. Anschließend können Sie die erfolgreich gespeicherte Datei in den Namen der ursprünglichen Datei umbenennen. Wie Sie testen, ob die Datei verwendet wird, erfahren Sie über die

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

    Zeile in meinem Code unten, und könnte in einem Windows-Dienst in einer Schleife erfolgen, wenn Sie eine bestimmte Datei haben, die Sie regelmäßig ansehen und löschen möchten, wenn Sie sie ersetzen möchten. Wenn Sie nicht immer dieselbe Datei haben, kann eine Textdatei oder Datenbanktabelle aktualisiert werden, die der Dienst immer auf Dateinamen überprüft und dann diese Prüfung auf Prozesse durchführt und anschließend die Prozessabbrüche und -löschungen darauf durchführt, wie ich beschreibe in der nächsten Option. Beachten Sie, dass Sie einen Benutzernamen und ein Kennwort für das Konto benötigen, die auf dem angegebenen Computer über Administratorrechte verfügen, um das Löschen und Beenden von Prozessen durchführen zu können.

  4. Wenn Sie nicht wissen, ob eine Datei beim Speichern verwendet wird, können Sie vor dem Speichern alle Prozesse schließen, die sie möglicherweise verwenden, z. B. Word, wenn es sich um ein Word-Dokument handelt.

    Wenn es lokal ist, können Sie dies tun:

    ProcessHandler.localProcessKill("winword.exe");

    Wenn es remote ist, können Sie dies tun:

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

    wo txtUserNameist in Form von DOMAIN\user.

  5. Angenommen, Sie kennen den Prozessnamen, der die Datei sperrt, nicht. Dann können Sie dies tun:

    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);
    }

    Beachten Sie, dass fileder UNC - Pfad sein muss: \\computer\share\yourdoc.docxum das Processherauszufinden, was Computer ist es auf und um p.MachineNamegültig zu sein.

    Nachfolgend finden Sie die Klasse, die diese Funktionen verwenden und für die ein Verweis hinzugefügt werden muss System.Management. Der Code wurde ursprünglich von Eric J geschrieben :

    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
quelle
2

Wie andere Antworten in diesem Thread gezeigt haben, müssen Sie den Code sorgfältig untersuchen, um diesen Fehler zu beheben und zu verstehen, wo die Datei gesperrt wird.

In meinem Fall habe ich die Datei als E-Mail-Anhang gesendet, bevor ich den Verschiebevorgang ausgeführt habe.

Daher wurde die Datei für einige Sekunden gesperrt, bis der SMTP-Client das Senden der E-Mail beendet hatte.

Die Lösung, die ich gewählt habe, bestand darin , zuerst die Datei zu verschieben und dann die E-Mail zu senden. Dies löste das Problem für mich.

Eine andere mögliche Lösung, auf die Hudson bereits hingewiesen hat, wäre gewesen, das Objekt nach der Verwendung zu entsorgen.

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
quelle
Wenn eine Datei verwendet File.Move()wird, funktioniert sie nicht und gibt den gleichen Fehler aus. Wenn Sie einer E-Mail nur eine Datei hinzufügen, glaube ich nicht, dass sie bei der Verwendung während des Attachments.Add()Vorgangs fehlerhaft ist, da dies nur ein Kopiervorgang ist. Wenn dies aus irgendeinem Grund der Fall ist, können Sie es in ein temporäres Verzeichnis kopieren, die Kopie anhängen und die kopierte Datei anschließend löschen. Aber ich denke nicht, dass, wenn das OP eine Datei ändern und diese verwenden möchte, diese Art von Lösung (für die Sie nicht den Code angezeigt haben, sondern nur den anhängenden Teil) funktionieren würde. .Dispose()ist immer eine gute Idee, aber hier nicht relevant, es sei denn, die Datei wurde in einer vorherigen Operation geöffnet.
Vapcguy
1

Ich hatte das folgende Szenario, das den gleichen Fehler verursachte:

  • Laden Sie Dateien auf den Server hoch
  • Entfernen Sie dann die alten Dateien, nachdem sie hochgeladen wurden

Die meisten Dateien waren klein, einige jedoch groß. Der Versuch, diese zu löschen, führte zu dem Fehler, dass nicht auf Dateien zugegriffen werden kann.

Es war nicht leicht zu finden, die Lösung war jedoch so einfach wie das Warten "auf die Ausführung der Aufgabe":

using (var wc = new WebClient())
{
   var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
   tskResult.Wait(); 
}
nützlichBee
quelle
-1

Mein unten stehender Code löst dieses Problem, aber ich schlage vor. Zunächst müssen Sie verstehen, was dieses Problem verursacht, und die Lösung ausprobieren, die Sie durch Ändern des Codes finden können

Ich kann einen anderen Weg zur Lösung dieses Problems angeben, aber eine bessere Lösung besteht darin, Ihre Codierungsstruktur zu überprüfen und zu analysieren, was dies bewirkt. Wenn Sie keine Lösung finden, können Sie diesen Code unten verwenden

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;
    }
 }
Asche
quelle
1
Einige Probleme mit diesem Code: 1) Wenn Sie anrufen müssen, haben GC.*()Sie wahrscheinlich andere Probleme mit Ihrem Code. 2) Die Nachricht ist lokalisiert und zerbrechlich . Verwenden Sie stattdessen das HRESULT. 3) Vielleicht möchten Sie mit schlafen Task.Delay()(und zehn Sekunden sind in vielen Fällen irgendwie zu lang). 4) Sie haben keine Exit-Bedingung: Dieser Code könnte für immer hängen bleiben. 5) Sie brauchen gotohier definitiv nicht . 6) Fangen Exceptionist normalerweise eine schlechte Idee, in diesem Fall auch, weil ... 6) Wenn etwas anderes passiert, schlucken Sie den Fehler.
Adriano Repetti
@AdrianoRepetti Mein erster Kommentar sagte, benutze diesen Code nicht. Versuche eine andere Lösung zu finden. Dies ist die letzte Option. Wenn dieser Fehler auftritt, wird der Code gestoppt. Wenn du dieses Fehlersystem behandelst, wartet das System auf die Freigabe der Datei und startet danach Arbeiten und ich habe keine anderen Probleme mit GC. * während der Verwendung dieses Codes. Ich habe bereits ein funktionierendes System mit diesem Code, so dass ich gepostet habe, kann für jemanden hilfreich sein.
Ash
Ich würde sagen , zu diesem Code nicht verwende immer (wegen der Punkte , die ich oben erwähnt) , und ich würde nicht diese betrachte Arbeits in einem prod System , aber das ist nur meine POV. Fühlen Sie sich frei, nicht zuzustimmen!
Adriano Repetti
1) Ich habe den Windows-Dienst verwendet, bei dem ich diesen verwendet habe, und ich habe GC verwendet. * Bis dahin habe ich kein Problem damit2) Ja, HRESULT kann eine bessere Option in Bezug auf den Codierungsstandard sein3) Abhängig von der Situation, in der Sie Zeit geben können, die ich gerade bearbeitet habe es auf 5 Sekunden 4) Auf jeden Fall ist es besser, das System einige Zeit zu warten, um Ressourcen freizugeben, anstatt das System mit Fehler zu stoppen. 5) Ja, ich bin mit Ihnen einverstanden. Die Ausnahmebehandlung ist nicht immer eine gute Idee, aber wenn Ihr Code-Snippet klein ist und Sie wissen dass hier ich Ausnahme behandeln kann, dann ist diese Lösung eine Option für Sie.
Ash
Siehe auch: docs.microsoft.com/en-us/archive/blogs/ricom/… . Der EINZIGE (und ich betone NUR) Fall, den ich verwenden musste, GC.Collect()war der Umgang mit einigen COM-Objekten.
Adriano Repetti