J'ai du code et quand il s'exécute, il jette un IOException
, en disant que
Le processus ne peut pas accéder au fichier 'nomfichier' car il est utilisé par un autre processus
Qu'est-ce que cela signifie et que puis-je faire à ce sujet?
Utiliser FileShare corrige le problème de l’ouverture du fichier même s’il était ouvert par un autre processus.
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
Avait un problème lors du téléchargement d'une image et ne pouvait pas supprimer et a trouvé une solution. GL hf
//C# .NET
var image = Image.FromFile(filePath);
image.Dispose(); // this removes all resources
//later...
File.Delete(filePath); //now works
J'ai eu cette erreur parce que je faisais File.Move à un chemin de fichier sans nom de fichier, besoin de spécifier le chemin complet dans la destination.
J'ai eu le scénario suivant qui causait la même erreur:
La plupart des fichiers étaient de petite taille, mais quelques-uns étaient volumineux. Par conséquent, toute tentative de suppression a entraîné l'erreur impossible d'accéder fichier.
Ce n’était pas facile à trouver, cependant, la solution était aussi simple que Attendre "que la tâche se termine":
using (var wc = new WebClient())
{
var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
tskResult.Wait();
}
L'erreur indique qu'un autre processus tente d'accéder au fichier. Peut-être que vous ou quelqu'un d'autre l'avez ouvert pendant que vous essayez d'écrire. "Lire" ou "Copier" ne cause généralement pas ceci, mais écrire ou appeler supprimer dessus le ferait.
Il y a quelques choses de base pour éviter cela, comme d'autres réponses l'ont mentionné:
FileStream
, placez-le dans un bloc using
avec un mode d'accès FileShare.ReadWrite
.Ex.
using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
Notez que FileAccess.ReadWrite
n'est pas possible si vous utilisez FileMode.Append
.
J'ai rencontré ce problème lorsque j'utilisais un flux d'entrée pour créer un File.SaveAs
lorsque le fichier était utilisé. Dans mon cas, j'ai constaté que je n'avais pas du tout besoin de le sauvegarder dans le système de fichiers. J'ai donc fini par le supprimer, mais j'aurais probablement pu créer un FileStream dans une instruction using
avec FileAccess.ReadWrite
, un peu comme le code ci-dessus.
Sauvegardez vos données dans un fichier différent et revenez en arrière pour supprimer l'ancien lorsqu'il s'avère que vous ne l'utilisez plus, puis renommez celui qui a été enregistré avec succès en le nom du fichier d'origine. La façon dont vous testez le fichier en cours d’utilisation est effectuée via la ligne List<Process> lstProcs = ProcessHandler.WhoIsLocking(file);
dans le code ci-dessous et peut être effectuée dans un service Windows, en boucle, si vous souhaitez regarder et supprimer régulièrement un fichier en particulier lorsque vous le souhaitez. le remplacer. Si vous ne possédez pas toujours le même fichier, vous pouvez mettre à jour un fichier texte ou une table de base de données. Le service vérifie toujours les noms de fichiers, puis effectue cette vérification des processus et exécute ensuite le processus supprime et supprime le processus, comme décrit ci-après. dans l'option suivante. Notez que vous aurez besoin d'un nom d'utilisateur de compte et d'un mot de passe dotés des privilèges d'administrateur sur l'ordinateur en question, bien sûr, pour effectuer la suppression et la fin des processus.
4a. Lorsque vous ne savez pas si un fichier sera utilisé lors de la sauvegarde, vous pouvez fermer tous les processus susceptibles de l'utiliser, tels que Word, s'il s'agit d'un document Word, avant la sauvegarde.
Si c'est local, vous pouvez faire ceci:
ProcessHandler.localProcessKill("winword.exe");
Si c'est distant, vous pouvez faire ceci:
ProcessHandler.remoteProcessKill(computerName, txtUserName, txtPassword, "winword.exe");
où txtUserName
est sous la forme de DOMAIN\user
.
4b. Disons que vous ne connaissez pas le nom du processus qui verrouille le fichier ... Vous pouvez faire ceci:
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);
}
Notez que file
doit être le chemin UNC: \\computer\share\yourdoc.docx
afin que Process
puisse déterminer sur quel ordinateur il se trouve et p.MachineName
soit valide. Vous trouverez ci-dessous la classe utilisée par ces fonctions, qui nécessite l'ajout d'une référence à System.Management
et provient de https://stackoverflow.com/a/20623311 :
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;
}
}
Comme d'autres réponses de ce fil l'ont fait remarquer, pour résoudre cette erreur, vous devez inspecter soigneusement le code afin de comprendre où le fichier est bloqué.
Dans mon cas, j’envoyais le fichier sous forme de pièce jointe à un courriel avant d’effectuer le déplacement.
Le fichier a donc été verrouillé pendant quelques secondes jusqu'à ce que le client SMTP ait fini d'envoyer le courrier électronique.
La solution que j’ai adoptée était de déplacer le fichier d’abord, puis d’envoyer le courrier électronique. Cela a résolu le problème pour moi.
Une autre solution possible, comme le faisait remarquer plus tôt Hudson, aurait été de disposer l'objet après utilisation.
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
}
}