C #에서 다른 프로세스에 의해 잠긴 파일을 어떻게 삭제합니까?
C #을 사용하여 다른 프로세스에 의해 잠긴 파일을 삭제하는 방법을 찾고 있습니다. 메서드가 파일을 잠그는 프로세스를 찾을 수 있어야한다고 생각합니다 (아마도 C #에서이 작업을 수행하는 방법을 잘 모르겠지만 핸들을 추적하여). 다음을 사용하여 파일 삭제를 완료하기 전에 해당 프로세스를 닫습니다 File.Delete()
.
다른 프로세스를 죽이는 것은 건강한 일이 아닙니다. 시나리오에 제거와 같은 것이 포함 된 경우 MoveFileEx
API 기능 을 사용 하여 다음에 재부팅 할 때 파일을 삭제하도록 표시 할 수 있습니다 .
다른 프로세스에서 사용중인 파일을 정말로 삭제해야한다고 생각되면 해결책을 고려하기 전에 실제 문제를 다시 고려하는 것이 좋습니다.
일반적인 방법은 다음과 같습니다. C #에서이 작업을 수행하고 싶다고 말 했으므로 여기에 있습니다.
- 파일이 잠긴 프로세스를 모르는 경우 각 프로세스의 핸들 목록을 검사하고 각 핸들을 쿼리하여 잠긴 파일을 식별하는지 확인해야합니다. C #에서이 작업을 수행하려면 필요한 네이티브 API를 호출하기 위해 P / Invoke 또는 중개 C ++ / CLI가 필요할 수 있습니다.
- 파일이 잠긴 프로세스를 파악한 후에는 작은 네이티브 DLL을 프로세스에 안전하게 주입해야합니다 (관리되는 DLL을 주입 할 수도 있지만이 작업은 더 복잡합니다. 또는 .NET 런타임에 연결).
- 그런 다음 해당 부트 스트랩 DLL은 CloseHandle 등을 사용하여 핸들을 닫습니다.
기본적으로 "잠긴"파일을 잠금 해제하는 방법은 문제가되는 프로세스의 주소 공간에 DLL 파일을 삽입하고 직접 닫는 것입니다. 네이티브 또는 관리 코드를 사용하여이 작업을 수행 할 수 있습니다. 어쨌든 소량의 네이티브 코드 또는 최소한 P / Invoke가 필요합니다.
유용한 링크 :
행운을 빕니다!
프로그래밍 방식으로 수행하려는 경우. 잘 모르겠습니다. 정말 반대하는 것이 좋습니다. 자신의 컴퓨터에서 문제를 해결 하려는 경우 SysInternals Process Explorer 가 도움이 될 수 있습니다.
실행하고 핸들 찾기 명령 (찾기 또는 핸들 메뉴에 있다고 생각)을 사용하고 파일 이름을 검색합니다. 핸들을 찾으면 강제로 닫을 수 있습니다.
그런 다음 파일을 삭제할 수 있습니다.
조심 당신은 그냥 아래에서 속담 러그를 꺼내 한 바와 같이, 이상하게 행동 핸들을 소유하는 프로그램을 일으킬 수 있습니다 이렇게, 그러나 당신이 당신의 자신의 잘못된 코드를 디버깅 할 때 잘 작동 할 때 또는 비주얼 스튜디오 / Windows 탐색기 오래 전에 파일을 닫으라고 말했지만 파일 핸들을 해제하지 않고 쓰레기입니다 ... 한숨 :-)
이 프로그램 Handle을 사용 하여 파일에 잠금이있는 프로세스를 찾을 수 있습니다. 이 도구는 명령 줄 도구이므로 출력을 사용하는 것 같습니다. 프로그래밍 방식으로 찾을 수 있을지 모르겠습니다.
파일 삭제가 기다릴 수 있다면 다음에 컴퓨터를 시작할 때 삭제할 파일을 지정할 수 있습니다.
시작
REGEDT32 (W2K)
하거나 다음REGEDIT (WXP)
으로 이동합니다.HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
W2K 및 WXP
W2K : 값 추가
편집
...
데이터 유형 :REG_MULTI_SZ
값 이름 :PendingFileRenameOperations
OKWXP : 새 다중 문자열 값
편집
enter
PendingFileRenameOperations
데이터 영역에
"\??\" + filename
삭제할 항목을 입력 합니다. LFN은 따옴표로 묶지 않고 입력 할 수 있습니다. 을 삭제하려면C:\Long Directory Name\Long File Name.exe
다음 데이터를 입력하십시오.\??\C:\Long Directory Name\Long File Name.exe
그런 다음을 누릅니다 OK.
"대상 파일 이름"은 null (영) 문자열입니다. 다음과 같이 입력됩니다.
W2K : 이진
편집 데이터 형식 선택 : 16 진수 문자열 끝에서 16 진수 클릭 0000 (4 개의 0) 입력
OKWXP :
값을 마우스 오른쪽 버튼으로 클릭하고
"이진 데이터 수정"을 선택
합니다. 16 진수 문자열의 끝을 클릭하고
0000을 입력합니다 (4 개의 0).
OK
REGEDT32/REGEDIT
파일을 삭제하려면 닫고 재부팅하십시오.
( 후손을 위해 임의의 포럼 에서 뻔뻔스럽게 도난당했습니다 .)
Orion Edwards의 조언을 사용하여 Sysinternals Process Explorer 를 다운로드하여 삭제하는 데 어려움을 겪고있는 파일이 실제로 Excel.Applications
내가 생각한 개체가 아니라 내 C # 코드 전송 메일 코드가 생성했다는 사실을 발견 할 수있었습니다. 이 파일에 대한 핸들을 열어 둔 Attachment 객체
이것을 본 후에는 Attachment 객체의 dispose 메서드를 아주 간단하게 호출했고 핸들이 해제되었습니다.
Sysinternals 탐색기를 통해 Visual Studio 2005 디버거와 함께 사용되는 것을 발견 할 수있었습니다.
이 도구를 강력히 추천합니다!
오, 내가 몇 년 전에 사용한 한 가지 큰 해킹은 Windows가 파일 을 삭제할 수는 없지만 파일을 이동할 수 있다는 것입니다.
의사 분류 코드 :
mv %WINDIR%\System32\mfc42.dll %WINDIR\System32\mfc42.dll.old
Install new mfc42.dll
Tell user to save work and restart applications
응용 프로그램이 다시 시작되면 (시스템을 재부팅 할 필요가 없음) 새를로드했으며 mfc42.dll
모두 정상적으로 작동했습니다 . PendingFileOperations
다음 번에 전체 시스템이 다시 시작될 때 이전 항목을 삭제하는 것과 함께 꽤 잘 작동했습니다.
이것은 유망 해 보입니다. 파일 핸들을 죽이는 방법 ....
http://www.timstall.com/2009/02/killing-file-handles-but-not-process.html
전체 파일 경로를 제공하는 코드를 사용할 수 있으며 List<Processes>
해당 파일을 잠그는 모든 항목 을 반환 합니다.
using System.Runtime.InteropServices;
using System.Diagnostics;
static public class FileUtil
{
[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;
}
}
그런 다음 프로세스 목록을 반복하고 닫고 파일을 삭제합니다.
string[] files = Directory.GetFiles(target_dir);
List<Process> lstProcs = new List<Process>();
foreach (string file in files)
{
lstProcs = ProcessHandler.WhoIsLocking(file);
if (lstProcs.Count > 0) // deal with the file lock
{
foreach (Process p in lstProcs)
{
if (p.MachineName == ".")
ProcessHandler.localProcessKill(p.ProcessName);
else
ProcessHandler.remoteProcessKill(p.MachineName, txtUserName.Text, txtPassword.Password, p.ProcessName);
}
File.Delete(file);
}
else
File.Delete(file);
}
파일이 로컬 컴퓨터에 있는지 여부에 따라 :
public static void localProcessKill(string processName)
{
foreach (Process p in Process.GetProcessesByName(processName))
{
p.Kill();
}
}
또는 네트워크 컴퓨터 :
public static void remoteProcessKill(string computerName, string fullUserName, string pword, string processName)
{
var connectoptions = new ConnectionOptions();
connectoptions.Username = fullUserName; // @"YourDomainName\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();
}
}
}
References:
How do I find out which process is locking a file using .NET?
Delete a directory where someone has opened a file
ReferenceURL : https://stackoverflow.com/questions/1040/how-do-i-delete-a-file-which-is-locked-by-another-process-in-c
'programing' 카테고리의 다른 글
C ++의 멤버 함수에 대한 const &, & 및 && 지정자 (0) | 2021.01.15 |
---|---|
형식 안전 열거 형을 만드는 방법은 무엇입니까? (0) | 2021.01.15 |
가장 좋은 "비밀번호 분실"방법은 무엇입니까? (0) | 2021.01.15 |
ess-mode에서 emacs가 underbar를 <-로 바꾸는 것을 막는 방법 (0) | 2021.01.15 |
LaTeX에서 "C ++"를 작성하는 방법 (0) | 2021.01.15 |