C#의 다른 프로세스에 의해 잠긴 파일을 어떻게 삭제합니까?

StackOverflow https://stackoverflow.com/questions/1040

  •  08-06-2019
  •  | 
  •  

문제

C#을 사용하여 다른 프로세스에 의해 잠긴 파일을 삭제하는 방법을 찾고 있습니다.나는 이 방법이 어떤 프로세스가 파일을 잠그고 있는지 찾을 수 있어야 한다고 생각합니다. (C#에서 이 작업을 수행하는 방법을 잘 모르겠지만 핸들을 추적하여) 다음을 사용하여 파일 삭제를 완료하기 전에 해당 프로세스를 닫습니다. File.Delete().

도움이 되었습니까?

해결책

다른 프로세스를 종료하는 것은 건전한 행동이 아닙니다.시나리오에 제거와 같은 내용이 포함된 경우 다음을 사용할 수 있습니다. MoveFileEx API 기능 다음 재부팅 시 파일을 삭제하도록 표시합니다.

다른 프로세스에서 사용 중인 파일을 꼭 삭제해야 하는 경우 솔루션을 고려하기 전에 실제 문제를 다시 고려하는 것이 좋습니다.

다른 팁

대표적인 방법은 다음과 같습니다.C#에서 이 작업을 수행하고 싶다고 말씀하셨으니 다음과 같습니다.

  1. 어떤 프로세스가 파일을 잠갔는지 모르는 경우 각 프로세스의 핸들 목록을 검사하고 각 핸들을 쿼리하여 잠긴 파일을 식별하는지 확인해야 합니다.C#에서 이 작업을 수행하려면 필요한 기본 API를 호출하기 위해 P/Invoke 또는 중간 C++/CLI가 필요할 수 있습니다.
  2. 어떤 프로세스에 파일이 잠겨 있는지 파악한 후에는 작은 기본 DLL을 프로세스에 안전하게 주입해야 합니다(관리되는 DLL을 주입할 수도 있지만 이는 더 복잡합니다. 그런 다음 시작해야 하기 때문입니다). 또는 .NET 런타임에 연결).
  3. 그런 다음 해당 부트스트랩 DLL은 CloseHandle 등을 사용하여 핸들을 닫습니다.

기본적으로:"잠긴" 파일을 잠금 해제하는 방법은 문제가 있는 프로세스의 주소 공간에 DLL 파일을 삽입하고 직접 닫는 것입니다.네이티브 코드나 관리 코드를 사용하여 이 작업을 수행할 수 있습니다.무슨 일이 있어도 소량의 네이티브 코드나 최소한 P/Invoke가 필요합니다.

유용한 링크:

행운을 빌어요!

프로그래밍 방식으로 수행하려는 경우.잘 모르겠어요...그리고 나는 그것에 반대하는 것을 정말로 추천하고 싶습니다.자신의 컴퓨터에서 문제를 해결하는 중이라면, SysInternals 프로세스 탐색기 당신을 도울 수 있습니다

실행하고 핸들 찾기 명령(찾기 또는 핸들 메뉴에 있는 것 같습니다)을 사용하고 파일 이름을 검색하세요.핸들을 찾으면 강제로 닫을 수 있습니다.

그런 다음 파일 등을 삭제할 수 있습니다.

조심하세요, 이렇게 하면 핸들을 소유한 프로그램이 이상하게 동작할 수 있습니다. 방금 그 아래에서 속담의 깔개를 꺼냈기 때문입니다. 그러나 잘못된 코드를 디버깅할 때나 Visual Studio/Windows 탐색기가 오래 전에 파일을 닫으라고 말했는데도 파일 핸들을 공개하지 않는 쓰레기입니다 ...한숨을 쉬다 :-)

이 프로그램을 사용하시면 됩니다, 핸들, 을 클릭하여 파일에 잠금이 설정된 프로세스를 찾으세요.명령줄 도구이므로 그 출력을 사용하는 것 같습니다.프로그래밍 방식으로 찾는 것이 확실하지 않습니다.

파일 삭제가 기다릴 수 있는 경우 다음에 컴퓨터가 시작될 때 삭제되도록 지정할 수 있습니다.

  1. 시작 REGEDT32 (W2K) 또는 REGEDIT (WXP) 다음으로 이동합니다.

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
    
  2. W2K 및 WXP

    • 주2천:
      편집하다
      값을 추가...
      데이터 형식: REG_MULTI_SZ
      값 이름: PendingFileRenameOperations
      좋아요

    • 경험치:
      편집하다
      새로운
      다중 문자열 값
      입력하다
      PendingFileRenameOperations

  3. 데이터 영역에 다음을 입력합니다. "\??\" + filename 삭제됩니다.LFN은 견적에 포함되지 않고 입력 할 수 있습니다.지우는 것 C:\Long Directory Name\Long File Name.exe, 다음 데이터를 입력합니다:

    \??\C:\Long Directory Name\Long File Name.exe
    

    그런 다음 좋아요.

  4. "대상 파일 이름"은 null(영) 문자열입니다.다음과 같이 입력됩니다.

    • 주2천:
      편집하다
      바이너리
      데이터 형식 선택:마녀
      16진수 문자열 끝을 클릭하세요.
      0000(0 4개)을 입력하세요.
      좋아요

    • 경험치:
      값을 마우스 오른쪽 버튼으로 클릭하세요.
      "바이너리 데이터 수정"을 선택하십시오.
      16진수 문자열 끝을 클릭하세요.
      0000(0 4개)을 입력하세요.
      좋아요

  5. 닫다 REGEDT32/REGEDIT 파일을 삭제하려면 재부팅하세요.

(뻔뻔하게도 훔친 임의의 포럼, 후손을 위해.)

Orion Edwards의 조언을 사용하여 Sysinternals를 다운로드했습니다. 프로세스 탐색기 그 결과 제가 삭제하는 데 어려움을 겪고 있던 파일이 실제로는 해당 파일이 아닌 다른 사람이 보관하고 있다는 사실을 알게 되었습니다. Excel.Applications 내 생각에는 내 C# 코드 전송 메일 코드가 이 파일에 대한 핸들을 열어 둔 첨부 파일 개체를 생성했다는 사실입니다.

이것을 본 후에는 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();
        }
    }
}

참고자료:
.NET을 사용하여 어떤 프로세스가 파일을 잠그고 있는지 어떻게 알 수 있나요?

누군가가 파일을 연 디렉토리 삭제

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top