Πώς μπορώ να διαγράψω ένα αρχείο που είναι κλειδωμένο από άλλη διεργασία σε C #;

ψήφοι
51

Ψάχνω για έναν τρόπο για να διαγράψετε ένα αρχείο που είναι κλειδωμένο από άλλη διαδικασία χρησιμοποιώντας C #. Υποψιάζομαι ότι η μέθοδος πρέπει να είναι σε θέση να βρείτε ποια διαδικασία κλείδωμα του αρχείου (ίσως με την καταδίωξη τις λαβές, αν και δεν είμαι σίγουρος πώς να το κάνουμε αυτό σε C #) και στη συνέχεια κλείστε αυτή τη διαδικασία πριν να είναι σε θέση να ολοκληρώσει το αρχείο διαγράψετε χρήση File.Delete().

Δημοσιεύθηκε 04/08/2008 στις 06:45
πηγή χρήστη
Σε άλλες γλώσσες...                            


8 απαντήσεις

ψήφοι
34

Killing άλλες διαδικασίες δεν είναι ένα υγιές πράγμα που κάνει. Αν το σενάριο σας περιλαμβάνει κάτι σαν απεγκατάσταση, μπορείτε να χρησιμοποιήσετε τη MoveFileExλειτουργία API για να επισημάνετε το αρχείο για διαγραφή κατά την επόμενη επανεκκίνηση.

Αν φαίνεται ότι πρέπει πραγματικά να διαγράψετε ένα αρχείο χρησιμοποιείται από άλλη διαδικασία, θα ήθελα να συστήσει εκ νέου λαμβάνοντας υπόψη το πραγματικό πρόβλημα πριν από την εξέταση τυχόν λύσεις.

Απαντήθηκε 04/08/2008 στις 07:01
πηγή χρήστη

ψήφοι
14

Η τυπική μέθοδος έχει ως εξής. Έχετε πει ότι θέλετε να το κάνετε αυτό σε C # τόσο εδώ πηγαίνει ...

  1. Αν δεν ξέρετε ποια διαδικασία έχει κλειδώσει το αρχείο, θα πρέπει να εξεταστεί λίστα λαβή κάθε διαδικασία, καθώς και το ερώτημα κάθε λαβή για να διαπιστωθεί εάν προσδιορίζει το κλειδωμένο αρχείο. Με αυτόν τον τρόπο σε C # πιθανότατα θα απαιτήσει P / Invoke ή ενδιάμεσο C ++ / CLI για να καλέσετε τα εγγενή APIs που θα χρειαστείτε.
  2. Μόλις κατάλαβα οποία διαδικασία (ες) έχει κλειδώσει το αρχείο, θα πρέπει να κάνετε την ένεση με ασφάλεια ένα μικρό εγγενή DLL στη διαδικασία (μπορείτε επίσης να κάνετε την ένεση ένα διαχειριζόμενο DLL, αλλά αυτό είναι πιό ακατάστατο, όπως μπορείτε στη συνέχεια να αρχίσουν ή αποδίδουν το .NET runtime).
  3. Αυτό εκκίνησης DLL στη συνέχεια κλείνει τη λαβή χρησιμοποιώντας CloseHandle, κ.λπ.

Ουσιαστικά: ο τρόπος για να ξεκλειδώσετε ένα «κλειδωμένο» αρχείο είναι να εισφέρει ένα αρχείο DLL στο χώρο διευθύνσεων της διαδικασίας παραβάτη και να κλείσετε μόνοι σας. Μπορείτε να το κάνετε αυτό χρησιμοποιώντας φυσικές ή διαχειριζόμενο κώδικα. Δεν έχει σημασία τι, θα πάμε να χρειάζονται μια μικρή ποσότητα εγγενή κώδικα ή τουλάχιστον P / Κλήση στον ίδιο.

Χρήσιμοι Σύνδεσμοι:

Καλή τύχη!

Απαντήθηκε 04/08/2008 στις 07:15
πηγή χρήστη

ψήφοι
7

Αν θέλετε να το κάνετε κάποιου προγράμματος. Δεν είμαι σίγουρος ... και θα ήθελα πραγματικά να συστήσω εναντίον της. Εάν είστε ακριβώς αντιμετώπιση προβλημάτων πράγματα για τη δική σας μηχανή, Explorer Sysinternals της διαδικασίας μπορεί να σας βοηθήσει

Εκτελέστε αυτό, χρησιμοποιήστε την εντολή Εύρεση Χειριστείτε (νομίζω ότι είναι είτε στο μενού βρουν ή να χειρίζονται), και την αναζήτηση για το όνομα του αρχείου σας. Μόλις βρεθεί η λαβή (ες), μπορείτε να δια της βίας να κλείσουν.

Στη συνέχεια μπορείτε να διαγράψετε το αρχείο και ούτω καθεξής.

Προσοχή , κάνει αυτό μπορεί να προκαλέσει το πρόγραμμα που κατέχει τις λαβές να συμπεριφέρεται παράξενα, όπως έχετε μόλις τράβηξε το παροιμιώδες χαλί κάτω από τα πόδια του, αλλά λειτουργεί καλά όταν debugging τη δική σας περιπλανώμενος κώδικα, ή όταν το Visual Studio / της Εξερεύνησης των Windows είναι να είναι χάλια και δεν απελευθερώνει το αρχείο χειρίζεται ακόμα κι αν τους είπε να κλείσει την ηλικία του αρχείου πριν ... ανάσα :-)

Απαντήθηκε 04/08/2008 στις 07:12
πηγή χρήστη

ψήφοι
4

Χρησιμοποιώντας Orion Edwards συμβουλές θα κατεβάσει το Sysinternals το Process Explorer η οποία με τη σειρά μου επέτρεψε να ανακαλύψει ότι το αρχείο είχα δυσκολίες διαγραφή ήταν στην πραγματικότητα κρατούνται όχι από το Excel.Applicationsαντικείμενο σκέφτηκα, αλλά το γεγονός ότι μου C # κώδικα στείλτε τον κωδικό ταχυδρομείου είχε δημιουργήσει ένα αντικείμενο Συνημμένο που άφησε μια λαβή σε αυτό το αρχείο ανοιχτό.

Μόλις είδα αυτό, πολύ απλά κάλεσε την μέθοδο διαθέσει το αντικείμενο Συνημμένο, και η λαβή κυκλοφόρησε.

Ο εξερευνητής Sysinternals μου επέτρεψε να ανακαλύψει αυτό που χρησιμοποιείται σε συνδυασμό με το πρόγραμμα εντοπισμού σφαλμάτων του Visual Studio 2005.

Θα ήθελα να συστήσω ιδιαίτερα αυτό το εργαλείο!

Απαντήθηκε 04/03/2009 στις 14:43
πηγή χρήστη

ψήφοι
4

Μπορείτε να χρησιμοποιήσετε αυτό το πρόγραμμα, λαβή , για να βρείτε ποια διαδικασία έχει την κλειδαριά στο αρχείο σας. Είναι ένα εργαλείο γραμμής εντολών, οπότε υποθέτω ότι μπορείτε να χρησιμοποιήσετε την έξοδο από αυτό ... Δεν είμαι σίγουρος για την εύρεση ότι προγραμματισμού.

Εάν η διαγραφή του αρχείου μπορεί να περιμένει, θα μπορούσατε να ορίσετε για τη διαγραφή όταν ο υπολογιστής σας την επόμενη εκκίνηση:

  1. Ξεκινήστε REGEDT32 (W2K)ή REGEDIT (WXP)και πλοηγηθείτε στο:

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
    
  2. W2K και wXP

    • W2K:
      Επεξεργασία
      προσθέσει αξία ...
      Τύπος δεδομένων: REG_MULTI_SZ
      Αξία Όνομα:PendingFileRenameOperations
      OK

    • WXP:
      Επεξεργασία
      Νέα
      Multi-String Value
      enter
      PendingFileRenameOperations

  3. Στην περιοχή δεδομένων, πληκτρολογήστε "\??\" + filenameπρέπει να διαγραφεί. LFNs μπορεί να εισαχθεί χωρίς να ενσωματώνονται σε εισαγωγικά. Για να διαγράψετε C:\Long Directory Name\Long File Name.exe, πληκτρολογήστε τα ακόλουθα δεδομένα:

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

    Στη συνέχεια πατήστε OK.

  4. Το «όνομα αρχείου προορισμού» είναι μηδενική (μηδέν) εγχόρδων. Είναι εγγράφεται ως εξής:

    • W2K:
      Επεξεργασία
      Binary
      επιλέξτε Data Format: Hex
      κλικ στο τέλος του string εξάγωνο
      εισάγετε 0000 (τέσσερα μηδενικά)
      OK

    • WXP:
      Κάντε δεξί κλικ η αξία
      επιλέξτε «Τροποποίηση Binary Data»
      , κάντε κλικ στο τέλος του string εξάγωνο
      εισάγετε 0000 (τέσσερα μηδενικά)
      OK

  5. Κλείστε REGEDT32/REGEDITκαι επανεκκίνηση για να διαγράψετε το αρχείο.

(Ανενδοίαστα κλαπεί από κάποιο τυχαίο φόρουμ , για χάρη υστεροφημία του.)

Απαντήθηκε 04/08/2008 στις 06:59
πηγή χρήστη

ψήφοι
3

Αυτό είναι πολλά υποσχόμενη. Ένας τρόπος για τη δολοφονία της λαβής αρχείο ....

http://www.timstall.com/2009/02/killing-file-handles-but-not-process.html

Απαντήθηκε 25/02/2009 στις 18:41
πηγή χρήστη

ψήφοι
3

Ω, ένα μεγάλο hack που απασχολούνται χρόνια πριν, είναι ότι τα Windows δεν θα σας αφήσει να διαγράψετε τα αρχεία, αλλά δεν σας επιτρέπουν να μετακινήσετε τους.

Ψευδο-είδος-του-code:

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τη διαγραφή της παλαιάς την επόμενη φορά που το όλο σύστημα επανεκκίνηση, λειτούργησε αρκετά καλά.

Απαντήθηκε 04/08/2008 στις 07:14
πηγή χρήστη

ψήφοι
2

Μπορείτε να χρησιμοποιήσετε κώδικα που σας παρέχει την πλήρη διαδρομή του αρχείου με, και θα επιστρέψει ένα 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;

Διαγραφή έναν κατάλογο όπου κάποιος έχει ανοίξει ένα αρχείο

Απαντήθηκε 27/01/2017 στις 20:45
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more