Vă mulțumim pentru susținere

Cum șterg un fișier care este blocat de un alt proces în C #?

Caut un mod de a șterge un fișier care este blocat de un alt proces folosind C #. Bănuiesc că metoda trebuie să fie capabilă să găsească ce proces blochează fișierul (probabil prin urmărirea mânerelor, deși nu sunt sigur cum să fac acest lucru în C #), apoi închideți acest proces înainte de a putea finaliza ștergerea fișierului folosind File.Delete () .

0
adăugat editat

6 răspunsuri

Dacă doriți să faceți acest lucru programatic. Nu sunt sigur ... și aș recomanda cu adevărat împotrivă. Dacă sunteți doar probleme de depanare pe propria mașină, SysInternals Process Explorer vă poate ajuta

Rulați-l, utilizați comanda Find Handle (cred că este fie în meniul de căutare sau de manipulare) și căutați numele fișierului. Odată ce mânerul (le) este găsit, puteți să-l închideți forțat.

Apoi, puteți șterge fișierul și așa mai departe.

Beware, doing this may cause the program which owns the handles to behave strangely, as you've just pulled the proverbial rug out from under it, but it works well when you are debugging your own errant code, or when visual studio / windows explorer is being crap and not releasing file handles even though you told them to close the file ages ago... sigh :-)

0
adăugat

Oh, un hack mare pe care l-am angajat cu ani în urmă, este că Windows nu vă va lăsa să ștergeți fișierele, dar vă permite să le mutați .

Pseudo-sort-de-cod:

mv %WINDIR%\System32\mfc42.dll %WINDIR\System32\mfc42.dll.old
Install new mfc42.dll
Tell user to save work and restart applications

Când aplicațiile au fost repornite (rețineți că nu am nevoie să reporniți mașina), au încărcat noul mfc42.dll și totul a fost bine. Acest lucru, cuplat cu PendingFileOperations pentru a șterge cel vechi data viitoare când întregul sistem a repornit, a funcționat destul de bine.

0
adăugat

Puteți utiliza acest program, pentru a afla ce proces are programul Manipulați . blocați fișierul. Este un instrument de linie de comandă, deci cred că utilizați ieșirea din asta ... Nu sunt sigur că o găsesc programat.

Dacă ștergeți fișierul poate aștepta, îl puteți specifica pentru ștergere la pornirea calculatorului următor:

  1. Start REGEDT32 (W2K) or REGEDIT (WXP) and navigate to:

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

    • W2K:
      Edit
      Add Value...
      Data Type: REG_MULTI_SZ
      Value Name: PendingFileRenameOperations
      OK

    • WXP:
      Edit
      New
      Multi-String Value
      enter
      PendingFileRenameOperations

  3. In the Data area, enter "\??\" + filename to be deleted. LFNs may be entered without being embedded in quotes. To delete C:\Long Directory Name\Long File Name.exe, enter the following data:

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

    Then press OK.

  4. The "destination file name" is a null (zero) string. It is entered as follows:

    • W2K:
      Edit
      Binary
      select Data Format: Hex
      click at the end of the hex string
      enter 0000 (four zeros)
      OK

    • WXP:
      Right-click the value
      choose "Modify Binary Data"
      click at the end of the hex string
      enter 0000 (four zeros)
      OK

  5. Close REGEDT32/REGEDIT and reboot to delete the file.

(furișat furat de la un forum aleator , pentru dragul posterității .)

0
adăugat

Omorârea altor procese nu este un lucru sănătos de făcut. Dacă scenariul dvs. implică o dezinstalare, puteți utiliza < puternic> MoveFileEx funcția API pentru a marca fișierul pentru ștergere la repornirea următoare.

Dacă se pare că într-adevăr trebuie să ștergeți un fișier utilizat de un alt proces, aș recomanda re-examinarea problemei reale înainte de a lua în considerare orice soluții.

0
adăugat
Rețineți această observație MSDN: MOVEFILE_DELAY_UNTIL_REBOOT - "... Această valoare poate fi utilizată numai dacă procesul se află în contextul unui utilizator care aparține grupului de administratori sau al contului LocalSystem ..."
adăugat autor Uwe Keim

Acest lucru pare promițător. O modalitate de a ucide mânerul fișierului ....

http://www.timstall.com/ 2009/02 / killing-file-manere-dar-nu-process.html

0
adăugat

You can use code that you supply the full file path to, and it will return a List of anything locking that file:

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

    /// 
/// Find out what process(es) have a lock on the specified file. ///
 
    /// 
Path of the file.
    /// Processes locking the file
    /// 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)
    /// 
    /// 
    static public List WhoIsLocking(string path)
    {
        uint handle;
        string key = Guid.NewGuid().ToString();
        List processes = new List();

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

Apoi, iterați lista proceselor și închideți-le și ștergeți fișierele:

    string[] files = Directory.GetFiles(target_dir);
    List lstProcs = new List();

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

În funcție de cazul în care fișierul se află pe computerul local:

public static void localProcessKill(string processName)
{
    foreach (Process p in Process.GetProcessesByName(processName))
    {
        p.Kill();
    }
}

sau un computer de rețea:

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?

Ștergeți un director unde cineva a deschis un fișier

0
adăugat