Your process is the only one to access that file 您确定其他流程是您自己的流程 . 如果您知道在程序的另一部分中打开该文件,那么首先必须检查每次使用后是否正确关闭文件句柄 . 以下是此错误的代码示例:
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
幸运的是 FileStream 实现了 IDisposable ,因此很容易将所有代码包装在 using 语句中:
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
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);
}
}
请注意我们在StackOverflow上经常看到的常见错误:
var stream = File.Open(path, FileOpen.Read);
var content = File.ReadAllText(path);
Your process is not the only one to access that file 如果您的进程不是唯一访问该文件的进程,那么交互可能会更难 . 重试模式将有所帮助(如果文件不应由其他任何人打开,但它是,那么您需要像Process Explorer这样的实用程序来检查谁在做什么) .
要避免的方法
如果适用,请始终使用using语句打开文件 . 如前一段所述,它会主动帮助您避免许多常见错误(请参阅this post以获取 how not to use it 上的示例) .
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}
在这个例子中,我展示了如何打开文件进行编写和共享以供阅读;请注意,在读取和写入重叠时,会导致数据未定义或无效 . 它's a situation that must be handled when reading. Also note that this doesn' t访问 stream 线程安全,因此除非以某种方式同步访问,否则不能与多个线程共享此对象(请参阅前面的链接) . 其他共享选项可用,它们开辟了更复杂的场景 . 有关详细信息,请参阅MSDN .
是否有可能 unlock 另一个进程使用的文件?它并不总是安全而且不那么容易,但是,it's possible .
0
我收到此错误是因为我正在执行File.Move到没有文件名的文件路径,需要在目标中指定完整路径 .
5
正如本主题中的其他答案所指出的,要解决此错误,您需要仔细检查代码,了解文件被锁定的位置 .
在我的情况下,我在执行移动操作之前将文件作为电子邮件附件发送 .
因此,文件被锁定几秒钟,直到SMTP客户端完成发送电子邮件 .
我采用的解决方案是 move the file first, and then send the email. 这解决了我的问题 .
正如Hudson早先指出的那样,另一种可能的解决方案是在使用后将物品丢弃 .
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
}
}
1
我有以下情况导致相同的错误:
将文件上传到服务器
然后在上传后删除旧文件
大多数文件都很小,但是有些文件很大,因此尝试删除这些文件导致无法访问文件错误 .
这并不容易找到,但解决方案就像Waiting "for the task to complete execution"一样简单:
using (var wc = new WebClient())
{
var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
tskResult.Wait();
}
9
上传图片时出现问题但无法删除并找到解决方案 . gl hf
//C# .NET
var image = Image.FromFile(filePath);
image.Dispose(); // this removes all resources
//later...
File.Delete(filePath); //now works
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;
}
}
-1
使用 FileShare 解决了打开文件的问题,即使它是由另一个进程打开的 .
using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}
7 回答
原因是什么?
错误消息非常清楚:您正在尝试访问文件,并且它无法访问,因为另一个进程(甚至同一进程)正在使用它(并且它不允许任何共享) .
调试
它可能很容易解决(或很难理解),具体取决于您的具体情况 . 我们来看看吧 .
Your process is the only one to access that file
您确定其他流程是您自己的流程 . 如果您知道在程序的另一部分中打开该文件,那么首先必须检查每次使用后是否正确关闭文件句柄 . 以下是此错误的代码示例:
幸运的是
FileStream
实现了IDisposable
,因此很容易将所有代码包装在using
语句中:此模式还将确保在异常情况下文件不会保持打开状态(可能是文件正在使用的原因:出现问题,没有人关闭它;有关示例,请参阅this post) .
如果一切看起来都很好(你确定你总是关闭你打开的每个文件,即使是例外情况)并且你有多个工作线程,那么你有两个选择:重新编写你的代码以序列化文件访问(并不总是可行但并不总是想要)或应用重试模式 . 它很容易实现(另请参阅有关disk I/O,networking和database access的更好示例) .
请注意我们在StackOverflow上经常看到的常见错误:
在这种情况下,
ReadAllText()
将失败,因为该文件正在使用中(之前的行中为File.Open()
) . 预先打开文件不仅是不必要的,而且也是错误的 . 这同样适用于所有File
函数,这些函数不返回您正在使用的文件的句柄:File.ReadAllText()
,File.WriteAllText()
,File.ReadAllLines()
,File.WriteAllLines()
和其他(如File.AppendAllXyz()
函数)将自行打开和关闭文件 .Your process is not the only one to access that file
如果您的进程不是唯一访问该文件的进程,那么交互可能会更难 . 重试模式将有所帮助(如果文件不应由其他任何人打开,但它是,那么您需要像Process Explorer这样的实用程序来检查谁在做什么) .
要避免的方法
如果适用,请始终使用using语句打开文件 . 如前一段所述,它会主动帮助您避免许多常见错误(请参阅this post以获取 how not to use it 上的示例) .
如果可能,尝试确定谁拥有对特定文件的访问权限,并通过一些众所周知的方法集中访问 . 例如,如果您有一个程序读写的数据文件,那么您应该将所有I / O代码放在一个类中 . 它将使调试变得更容易(因为你总是可以在那里放置一个断点,看看谁在做什么),并且它也是多重访问的同步点(如果需要) .
不要忘记I / O操作总是会失败,一个常见的例子就是:
如果有人在
File.Exists()
之后但在File.Delete()
之前删除了该文件,那么它会在您可能错误安全的地方抛出IOException
.只要有可能,应用重试模式,如果您正在使用
FileSystemWatcher
,请考虑推迟操作(因为您将收到通知,但应用程序可能仍在使用该文件) .Advanced scenarios
它从头开始读到写到最后,你至少有两个选择 .
1)与适当的同步功能共享相同的
FileStream
(因为 it is not thread-safe ) . 有关示例,请参阅this和this个帖子 .2)使用
FileShare
枚举来指示操作系统允许其他进程(或您自己进程的其他部分)同时访问同一文件 .在这个例子中,我展示了如何打开文件进行编写和共享以供阅读;请注意,在读取和写入重叠时,会导致数据未定义或无效 . 它's a situation that must be handled when reading. Also note that this doesn' t访问
stream
线程安全,因此除非以某种方式同步访问,否则不能与多个线程共享此对象(请参阅前面的链接) . 其他共享选项可用,它们开辟了更复杂的场景 . 有关详细信息,请参阅MSDN .一般来说,N个进程可以从同一个文件中一起读取,但只有一个应该写入,在受控方案中,您甚至可以启用并发写入,但这不能在本答案中的几个文本段落中概括 .
是否有可能 unlock 另一个进程使用的文件?它并不总是安全而且不那么容易,但是,it's possible .
我收到此错误是因为我正在执行File.Move到没有文件名的文件路径,需要在目标中指定完整路径 .
正如本主题中的其他答案所指出的,要解决此错误,您需要仔细检查代码,了解文件被锁定的位置 .
在我的情况下,我在执行移动操作之前将文件作为电子邮件附件发送 .
因此,文件被锁定几秒钟,直到SMTP客户端完成发送电子邮件 .
我采用的解决方案是 move the file first, and then send the email. 这解决了我的问题 .
正如Hudson早先指出的那样,另一种可能的解决方案是在使用后将物品丢弃 .
我有以下情况导致相同的错误:
将文件上传到服务器
然后在上传后删除旧文件
大多数文件都很小,但是有些文件很大,因此尝试删除这些文件导致无法访问文件错误 .
这并不容易找到,但解决方案就像Waiting "for the task to complete execution"一样简单:
上传图片时出现问题但无法删除并找到解决方案 . gl hf
该错误表示另一个进程正在尝试访问该文件 . 也许你或其他人在你试图写信时打开它 . “读取”或“复制”通常不会导致这种情况,但是写入或调用删除就可以了 .
有一些基本的东西要避免这种情况,正如其他答案所提到的:
FileStream
操作中,将其置于具有FileShare.ReadWrite
访问模式的using
块中 .防爆 .
请注意,如果您使用
FileMode.Append
,则无法使用FileAccess.ReadWrite
.当我使用输入流在文件使用时执行
File.SaveAs
时,我遇到了这个问题 . 在我的情况下,我发现,我没有尝试使用FileAccess.ReadWrite
在using
语句中创建一个FileStream,就像上面的代码一样 .将数据保存为另一个文件,当发现不再使用时,返回删除旧数据,然后将成功保存的文件重命名为原始文件的名称是一个选项 . 如何测试正在使用的文件是通过我下面的代码中的
List<Process> lstProcs = ProcessHandler.WhoIsLocking(file);
行完成的,并且可以在Windows服务中,在循环中完成,如果您有想要观看的特定文件并在需要时定期删除代替它 . 如果您不需要在给定计算机上具有管理员权限的帐户用户名和密码,当然,要执行删除和结束进程 .4A . 当您在尝试保存文件时不知道文件是否正在使用时,您可以在保存之前关闭可能正在使用它的所有进程,如Word,如果它是Word文档 .
如果是本地的,您可以这样做:
如果它是远程的,你可以这样做:
其中
txtUserName
的形式为DOMAIN\user
.4B . 假设您不知道锁定文件的进程名称...您可以这样做:
请注意
file
必须是UNC路径:\\computer\share\yourdoc.docx
,以便Process
找出它所在的计算机和p.MachineName
有效 . 下面是这些函数使用的类,它需要添加对System.Management
的引用,并且来自https://stackoverflow.com/a/20623311:使用 FileShare 解决了打开文件的问题,即使它是由另一个进程打开的 .