Không thể xóa thư mục với Directory.Delete (đường dẫn, đúng)


383

Tôi đang sử dụng .NET 3.5, đang cố gắng xóa đệ quy một thư mục bằng cách sử dụng:

Directory.Delete(myPath, true);

Tôi hiểu rằng điều này sẽ ném nếu các tập tin đang sử dụng hoặc có vấn đề về quyền, nhưng nếu không thì nó sẽ xóa thư mục và tất cả nội dung của nó.

Tuy nhiên, tôi thỉnh thoảng nhận được điều này:

System.IO.IOException: The directory is not empty.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive)
    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive)
    ...

Tôi không ngạc nhiên khi phương pháp đôi khi ném, nhưng tôi ngạc nhiên khi nhận được thông điệp đặc biệt này khi đệ quy là đúng. (Tôi biết thư mục không trống.)

Có lý do nào tôi muốn thấy điều này thay vì AccessViolationException không?


13
Bạn sẽ không thấy AccessViolationException - đó là cho các hoạt động con trỏ không hợp lệ, không phải cho truy cập đĩa.
Joe White

1
Đây dường như là một số vấn đề IO khác ngoài thư mục không trống, như xử lý tệp mở hoặc một cái gì đó. Tôi sẽ thử sử dụng tùy chọn xóa đệ quy, sau đó để tìm IOException, tìm kiếm và đóng bất kỳ xử lý tệp đang mở nào, sau đó thử lại. Có một cuộc thảo luận về vấn đề đó ở đây: stackoverflow.com/questions/177146/ từ
Dan Csharpster

Câu trả lời:


231

Lưu ý của biên tập viên: Mặc dù câu trả lời này có chứa một số thông tin hữu ích, nhưng thực tế không chính xác về hoạt động của Directory.Delete. Xin vui lòng đọc các ý kiến ​​cho câu trả lời này, và câu trả lời khác cho câu hỏi này.


Tôi đã gặp vấn đề này trước đây.

Nguyên nhân của vấn đề là chức năng này không xóa các tệp nằm trong cấu trúc thư mục. Vì vậy, những gì bạn sẽ cần làm là tạo một hàm xóa tất cả các tệp trong cấu trúc thư mục rồi đến tất cả các thư mục trước khi xóa chính thư mục đó. Tôi biết điều này đi ngược lại với tham số thứ hai nhưng đó là một cách tiếp cận an toàn hơn nhiều. Ngoài ra, bạn có thể sẽ muốn xóa các thuộc tính truy cập READ-CHỈ khỏi các tệp ngay trước khi bạn xóa chúng. Nếu không điều đó sẽ đưa ra một ngoại lệ.

Chỉ cần tát mã này vào dự án của bạn.

public static void DeleteDirectory(string target_dir)
{
    string[] files = Directory.GetFiles(target_dir);
    string[] dirs = Directory.GetDirectories(target_dir);

    foreach (string file in files)
    {
        File.SetAttributes(file, FileAttributes.Normal);
        File.Delete(file);
    }

    foreach (string dir in dirs)
    {
        DeleteDirectory(dir);
    }

    Directory.Delete(target_dir, false);
}

Ngoài ra, đối với cá nhân tôi, tôi thêm một hạn chế đối với các khu vực của máy được phép xóa vì bạn có muốn ai đó gọi chức năng này trên C:\WINDOWS (%WinDir%)hoặc C:\.


117
Thật vô nghĩa. Directory.Delete (myPath, true) là một tình trạng quá tải xóa tất cả các tệp trong cấu trúc thư mục. Nếu bạn muốn nhận sai, hãy trả lời sai với câu trả lời của Ryan S.
Sig. Tolleranza

35
+1 vì mặc dù Directory.Delete () không xóa các tệp bên trong các thư mục con của nó (với recursive = true), nó sẽ ném "IOException: Directory không trống" nếu một trong các thư mục con hoặc tệp chỉ đọc. Vì vậy, giải pháp này hoạt động tốt hơn Directory.Delete ()
Anthony Brien

17
Tuyên bố của bạn Directory.Delete(path, true)không xóa các tập tin là sai. Xem MSDN msdn.microsoft.com/en-us/l
Library / fxeahc5f.aspx

20
-1 Ai đó có thể vui lòng đặt một dấu hiệu rõ ràng rằng tính hợp lệ của phương pháp này rất đáng nghi ngờ. Nếu Directory.Delete(string,bool)thất bại, một cái gì đó bị khóa hoặc không được phép và không có một kích thước phù hợp với tất cả các giải pháp cho vấn đề như vậy. Mọi người cần phải giải quyết vấn đề đó trong bối cảnh của họ và chúng tôi sẽ không phát triển một ý tưởng lớn về vấn đề này (với thử lại và nuốt ngoại lệ) và hy vọng một kết quả tốt.
Ruben Bartelink

37
Cảnh giác với cách tiếp cận này nếu thư mục của bạn xóa có các phím tắt / liên kết tượng trưng đến các thư mục khác - cuối cùng bạn có thể xóa nhiều hơn bạn mong đợi
Chanakya

182

Nếu bạn đang cố gắng xóa đệ quy thư mục avà thư mục a\bđang mở trong Explorer, bsẽ bị xóa nhưng bạn sẽ nhận được lỗi 'thư mục không trống' angay cả khi nó trống khi bạn đi và nhìn. Thư mục hiện tại của bất kỳ ứng dụng nào (bao gồm cả Explorer) vẫn giữ một tay cầm cho thư mục . Khi bạn gọi Directory.Delete(true), nó sẽ xóa từ dưới lên : b, sau đó a. Nếu bđược mở trong Explorer, Explorer sẽ phát hiện việc xóa b, thay đổi thư mục lên trên cd ..và dọn sạch các thẻ điều khiển mở. Do hệ thống tệp hoạt động không đồng bộ, nên Directory.Deletehoạt động không thành công do xung đột với Explorer.

Giải pháp chưa hoàn chỉnh

Ban đầu tôi đã đăng giải pháp sau đây, với ý tưởng làm gián đoạn luồng hiện tại để cho phép Explorer có thời gian giải phóng tay cầm thư mục.

// incomplete!
try
{
    Directory.Delete(path, true);
}
catch (IOException)
{
    Thread.Sleep(0);
    Directory.Delete(path, true);
}

Nhưng điều này chỉ hoạt động nếu thư mục mở là con ngay lập tức của thư mục bạn đang xóa. Nếu a\b\c\dđược mở trong Explorer và bạn sử dụng tính năng này a, kỹ thuật này sẽ thất bại sau khi xóa dc.

Một giải pháp tốt hơn

Phương pháp này sẽ xử lý xóa cấu trúc thư mục sâu ngay cả khi một trong các thư mục cấp thấp hơn được mở trong Explorer.

/// <summary>
/// Depth-first recursive delete, with handling for descendant 
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
    foreach (string directory in Directory.GetDirectories(path))
    {
        DeleteDirectory(directory);
    }

    try
    {
        Directory.Delete(path, true);
    }
    catch (IOException) 
    {
        Directory.Delete(path, true);
    }
    catch (UnauthorizedAccessException)
    {
        Directory.Delete(path, true);
    }
}

Mặc dù có thêm công việc đệ quy, chúng tôi vẫn phải xử lý những UnauthorizedAccessExceptiongì có thể xảy ra trên đường đi. Không rõ liệu lần thử xóa đầu tiên có mở đường cho lần thứ hai, lần thành công hay không, nếu đó chỉ là sự chậm trễ về thời gian được đưa ra bởi việc ném / bắt một ngoại lệ cho phép hệ thống tệp bắt kịp.

Bạn có thể giảm số lượng các trường hợp ngoại lệ được ném và bắt trong các điều kiện điển hình bằng cách thêm một Thread.Sleep(0)ở đầu trykhối. Ngoài ra, có một rủi ro là dưới tải hệ thống nặng, bạn có thể bay qua cả hai Directory.Deletelần thử và thất bại. Xem xét giải pháp này là điểm khởi đầu để xóa đệ quy mạnh mẽ hơn.

Câu trả lời chung

Giải pháp này chỉ giải quyết các đặc thù của việc tương tác với Windows Explorer. Nếu bạn muốn thao tác xóa khối cứng, một điều cần lưu ý là mọi thứ (trình quét vi-rút, bất cứ thứ gì) đều có thể xử lý mở đối với những gì bạn đang cố xóa bất cứ lúc nào. Vì vậy, bạn phải thử lại sau. Bao nhiêu lần sau và bao nhiêu lần bạn thử, tùy thuộc vào mức độ quan trọng của đối tượng bị xóa. Như MSDN chỉ ra ,

Mã lặp tập tin mạnh mẽ phải tính đến nhiều phức tạp của hệ thống tập tin.

Tuyên bố vô tội này, chỉ được cung cấp với một liên kết đến tài liệu tham khảo NTFS, nên làm cho tóc của bạn đứng lên.

( Chỉnh sửa : Rất nhiều. Câu trả lời này ban đầu chỉ có giải pháp đầu tiên, không đầy đủ.)


11
Nó xuất hiện gọi Directory.Delete (path, true) trong khi đường dẫn hoặc một trong các thư mục / tệp trong đường dẫn được mở hoặc được chọn trong Windows Explorer sẽ đưa ra IOException. Đóng Windows Explorer và chạy lại mã hiện tại của tôi với thử / bắt được đề xuất ở trên hoạt động tốt.
David Alpert

1
Tôi không thể hiểu làm thế nào và tại sao nó hoạt động nhưng nó hoạt động với tôi trong khi thiết lập các thuộc tính tệp và viết hàm đệ quy của riêng tôi thì không.
Stilgar

1
@CarlosLiu Bởi vì nó đang cho "Explorer cơ hội phát hành tay cầm thư mục"
Dmitry Gonchar

4
Điều đang xảy ra là hệ thống yêu cầu Explorer "giải phóng tay cầm thư mục", sau đó cố gắng xóa thư mục. Nếu xử lý thư mục không bị xóa kịp thời, một ngoại lệ được đưa ra và catchkhối được thực thi (trong khi đó, Explorer vẫn đang phát hành thư mục, vì không có lệnh nào được gửi để bảo nó không làm như vậy). Cuộc gọi đến Thread.Sleep(0)có thể hoặc không cần thiết, vì catchkhối này đã cho hệ thống thêm một chút thời gian, nhưng nó cung cấp thêm một chút an toàn cho chi phí thấp. Sau đó, Deleteđược gọi, với thư mục đã được phát hành.
Zachary Kniebel

1
@PandaWood thực sự chỉ có giấc ngủ này (100) làm việc cho tôi. Ngủ (0) không hoạt động. Tôi không biết chuyện gì đang xảy ra và làm thế nào để giải quyết vấn đề này. Ý tôi là, nếu nó phụ thuộc vào tải máy chủ và trong tương lai thì nên có 300 hoặc 400? Làm sao để biết điều đó. Phải là một cách thích hợp khác ...
La Mã

43

Trước khi đi xa hơn, hãy kiểm tra các lý do sau đây nằm trong tầm kiểm soát của bạn:

  • Là thư mục được thiết lập như một thư mục hiện tại của quá trình của bạn? Nếu có, thay đổi nó thành một cái gì đó khác trước.
  • Bạn đã mở một tập tin (hoặc tải một DLL) từ thư mục đó? (và quên đóng / dỡ nó)

Nếu không, hãy kiểm tra các lý do hợp pháp sau đây ngoài tầm kiểm soát của bạn:

  • Có những tệp được đánh dấu là chỉ đọc trong thư mục đó.
  • Bạn không có quyền xóa một số tệp đó.
  • Tệp hoặc thư mục con được mở trong Explorer hoặc ứng dụng khác.

Nếu bất kỳ vấn đề nào ở trên là vấn đề, bạn nên hiểu lý do tại sao nó xảy ra trước khi cố gắng cải thiện mã xóa của bạn. Ứng dụng của bạn nên xóa các tệp chỉ đọc hoặc không thể truy cập? Ai đã đánh dấu chúng theo cách đó, và tại sao?

Một khi bạn đã loại trừ những lý do trên, vẫn có khả năng thất bại giả. Việc xóa sẽ thất bại nếu bất kỳ ai nắm giữ bất kỳ tệp hoặc thư mục nào bị xóa và có nhiều lý do khiến ai đó có thể liệt kê thư mục hoặc đọc tệp của nó:

  • chỉ mục tìm kiếm
  • chống vi-rút
  • phần mềm sao lưu

Cách tiếp cận chung để đối phó với các thất bại giả là thử nhiều lần, tạm dừng giữa các lần thử. Rõ ràng là bạn không muốn tiếp tục cố gắng mãi mãi, vì vậy bạn nên từ bỏ sau một số lần thử nhất định và ném ngoại lệ hoặc bỏ qua lỗi. Như thế này:

private static void DeleteRecursivelyWithMagicDust(string destinationDir) {
    const int magicDust = 10;
    for (var gnomes = 1; gnomes <= magicDust; gnomes++) {
        try {
            Directory.Delete(destinationDir, true);
        } catch (DirectoryNotFoundException) {
            return;  // good!
        } catch (IOException) { // System.IO.IOException: The directory is not empty
            System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);

            // see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
            Thread.Sleep(50);
            continue;
        }
        return;
    }
    // depending on your use case, consider throwing an exception here
}

Theo tôi, một người trợ giúp như thế nên được sử dụng cho tất cả các lần xóa vì thất bại giả luôn luôn có thể xảy ra. Tuy nhiên, BẠN NÊN QUẢNG CÁO MÃ SỐ NÀY ĐỂ SỬ DỤNG TRƯỜNG HỢP CỦA BẠN, không chỉ sao chép một cách mù quáng.

Tôi đã gặp lỗi giả đối với thư mục dữ liệu nội bộ do ứng dụng của tôi tạo ra, nằm dưới% LocalAppData%, vì vậy phân tích của tôi diễn ra như sau:

  1. Thư mục chỉ được kiểm soát bởi ứng dụng của tôi và người dùng không có lý do chính đáng để đi và đánh dấu những thứ là chỉ đọc hoặc không thể truy cập trong thư mục đó, vì vậy tôi không thử xử lý trường hợp đó.

  2. Không có thứ gì có giá trị do người dùng tạo trong đó, vì vậy không có nguy cơ mạnh mẽ xóa thứ gì đó do nhầm lẫn.

  3. Là một thư mục dữ liệu nội bộ, tôi không hy vọng nó sẽ được mở trong trình thám hiểm, ít nhất tôi không cảm thấy cần phải xử lý cụ thể vụ việc (ví dụ: tôi xử lý vụ việc đó thông qua hỗ trợ).

  4. Nếu tất cả các lần thử đều thất bại, tôi chọn bỏ qua lỗi. Trường hợp xấu nhất, ứng dụng không giải nén được một số tài nguyên mới hơn, gặp sự cố và nhắc người dùng liên hệ với bộ phận hỗ trợ, điều này được tôi chấp nhận miễn là điều đó không xảy ra thường xuyên. Hoặc, nếu ứng dụng không gặp sự cố, nó sẽ để lại một số dữ liệu cũ, điều này một lần nữa được tôi chấp nhận.

  5. Tôi chọn giới hạn thử lại ở mức 500ms (50 * 10). Đây là một ngưỡng tùy ý hoạt động trong thực tế; Tôi muốn ngưỡng này đủ ngắn để người dùng không giết ứng dụng, vì nghĩ rằng nó đã ngừng phản hồi. Mặt khác, nửa giây là nhiều thời gian để người vi phạm hoàn thành việc xử lý thư mục của tôi. Đánh giá từ các câu trả lời SO khác đôi khi có Sleep(0)thể chấp nhận được, rất ít người dùng sẽ trải nghiệm nhiều hơn một lần thử lại.

  6. Tôi thử lại sau mỗi 50ms, đó là một con số tùy ý. Tôi cảm thấy rằng nếu một tệp đang được xử lý (lập chỉ mục, kiểm tra) khi tôi cố xóa nó, 50ms là khoảng thời gian thích hợp để mong đợi việc xử lý được hoàn thành trong trường hợp của tôi. Ngoài ra, 50ms đủ nhỏ để không dẫn đến sự chậm lại đáng chú ý; một lần nữa, Sleep(0)dường như là đủ trong nhiều trường hợp, vì vậy chúng tôi không muốn trì hoãn quá nhiều.

  7. Mã thử lại trên bất kỳ trường hợp ngoại lệ IO. Tôi thường không mong đợi bất kỳ trường hợp ngoại lệ nào truy cập% LocalAppData%, vì vậy tôi đã chọn tính đơn giản và chấp nhận rủi ro trì hoãn 500ms trong trường hợp ngoại lệ hợp pháp xảy ra. Tôi cũng không muốn tìm ra cách phát hiện ngoại lệ chính xác mà tôi muốn thử lại.


7
PPS Một vài tháng sau, tôi vui mừng báo cáo rằng đoạn mã (hơi điên rồ) này đã giải quyết hoàn toàn vấn đề. Yêu cầu hỗ trợ về vấn đề này giảm xuống không (từ khoảng 1-2 mỗi tuần).
Andrey Tarantsov

1
+0 Trong khi đây là một mạnh mẽ hơn và ít 'ở đây; giải pháp hoàn hảo cho bạn 'hơn stackoverflow.com/a/7518831/11635 , đối với tôi cũng áp dụng tương tự - lập trình bằng sự trùng hợp - xử lý cẩn thận. Một điểm hữu ích được thể hiện trong mã của bạn là nếu bạn định thử lại, bạn cần phải xem xét rằng bạn đang ở trong một cuộc đua với sự mơ hồ về việc liệu Thư mục có 'Đã qua' từ lần thử cuối cùng [và một Directory.Existsngười bảo vệ niave sẽ không giải quyết điều đó.]
Ruben Bartelink

1
thích nó ... không biết tôi đang làm gì mà điều này luôn là một điểm đau đối với tôi ... nhưng không phải vì tôi có thư mục mở trong explorer ... không có nhiều sự ồn ào trên internet về điều này nhiều hơn -hoặc ít lỗi hơn ... ít nhất là tôi và Andrey có cách đối phó với nó :)
TCC

2
@RubenBartelink OK, vì vậy tôi nghĩ chúng ta có thể đồng ý về điều này: đăng một đoạn mã hoạt động cho một ứng dụng cụ thể (và không bao giờ có nghĩa là phù hợp với mọi trường hợp) vì câu trả lời SO sẽ là một sự bất đồng đối với nhiều người mới và / hoặc nhà phát triển không biết gì. Tôi đã cho nó như một điểm khởi đầu để tùy biến, nhưng vâng, một số người sẽ sử dụng nó như vậy, và đó là một điều xấu.
Andrey Tarantsov

2
@nopara Bạn không cần so sánh; nếu chúng ta ra khỏi vòng lặp, chúng ta đã thất bại. Và có, trong nhiều trường hợp, bạn sẽ muốn ném ngoại lệ, sau đó thêm mã xử lý lỗi thích hợp lên ngăn xếp, có khả năng với một thông báo hiển thị cho người dùng.
Andrey Tarantsov

18

Trả lời Async hiện đại

Câu trả lời được chấp nhận là hoàn toàn sai, nó có thể hoạt động đối với một số người vì thời gian để lấy tệp từ đĩa giải phóng bất cứ điều gì đang khóa các tệp. Thực tế là, điều này xảy ra vì các tệp bị khóa bởi một số tiến trình / luồng / hành động khác. Các câu trả lời khác sử dụng Thread.Sleep(Yuck) để thử lại xóa thư mục sau một thời gian. Câu hỏi này cần xem xét lại với một câu trả lời hiện đại hơn.

public static async Task<bool> TryDeleteDirectory(
   string directoryPath,
   int maxRetries = 10,
   int millisecondsDelay = 30)
{
    if (directoryPath == null)
        throw new ArgumentNullException(directoryPath);
    if (maxRetries < 1)
        throw new ArgumentOutOfRangeException(nameof(maxRetries));
    if (millisecondsDelay < 1)
        throw new ArgumentOutOfRangeException(nameof(millisecondsDelay));

    for (int i = 0; i < maxRetries; ++i)
    {
        try
        {
            if (Directory.Exists(directoryPath))
            {
                Directory.Delete(directoryPath, true);
            }

            return true;
        }
        catch (IOException)
        {
            await Task.Delay(millisecondsDelay);
        }
        catch (UnauthorizedAccessException)
        {
            await Task.Delay(millisecondsDelay);
        }
    }

    return false;
}

Bài kiểm tra đơn vị

Các thử nghiệm này cho thấy một ví dụ về cách một tệp bị khóa có thể gây ra Directory.Deletelỗi và cách TryDeleteDirectoryphương pháp trên khắc phục sự cố.

[Fact]
public async Task TryDeleteDirectory_FileLocked_DirectoryNotDeletedReturnsFalse()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            var result = await TryDeleteDirectory(directoryPath, 3, 30);
            Assert.False(result);
            Assert.True(Directory.Exists(directoryPath));
        }
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

[Fact]
public async Task TryDeleteDirectory_FileLockedThenReleased_DirectoryDeletedReturnsTrue()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        Task<bool> task;
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            task = TryDeleteDirectory(directoryPath, 3, 30);
            await Task.Delay(30);
            Assert.True(Directory.Exists(directoryPath));
        }

        var result = await task;
        Assert.True(result);
        Assert.False(Directory.Exists(directoryPath));
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

Bạn có thể mở rộng về những gì bạn có nghĩa là "hiện đại"? Những lợi ích của phương pháp của bạn là gì? Tại sao những người khác, theo ý kiến ​​của bạn sai?
TinyRacoon

1
Những người khác không sai. Họ chỉ sử dụng API của già như Thread.Sleepmà bạn nên tránh ngày hôm nay và sử dụng async/ awaitTask.Delayđể thay thế. Điều đó có thể hiểu được, đây là một câu hỏi rất cũ.
Muhammad Rehan Saeed

Cách tiếp cận này sẽ không hoạt động trong VB.Net (ít nhất là không phải với chuyển đổi theo dòng rất chính xác) doBC36943 'Await' cannot be used inside a 'Catch' statement, a 'Finally' statement, or a 'SyncLock' statement.
amonroejj

@amonroejj Bạn phải sử dụng phiên bản cũ hơn. Điều đó đã được sửa.
Muhammad Rehan Saeed

Cải thiện nhỏ thay vì trả về đúng if (!Directory.Exists(directoryPath)) { return true; } await Task.Delay(millisecondsDelay); để đợi cho đến khi thư mục thực sự biến mất
fuchs777

16

Một điều quan trọng cần được đề cập (tôi đã thêm nó dưới dạng nhận xét nhưng tôi không được phép) là hành vi quá tải đã thay đổi từ .NET 3.5 sang .NET 4.0.

Directory.Delete(myPath, true);

Bắt đầu từ .NET 4.0, nó xóa các tệp trong thư mục nhưng KHÔNG ở 3.5. Điều này có thể được nhìn thấy trong tài liệu MSDN là tốt.

.NET 4.0

Xóa thư mục đã chỉ định và, nếu được chỉ định, mọi thư mục con và tệp trong thư mục.

.NET 3.5

Xóa một thư mục trống và, nếu được chỉ định, bất kỳ thư mục con và tệp trong thư mục.


3
Tôi nghĩ rằng đó chỉ là một thay đổi tài liệu ... nếu nó chỉ xóa một "thư mục trống", điều gì có nghĩa là xóa các tệp trong thư mục, với tham số 2 °? Nếu nó trống thì không có tập tin nào ...
Pisu

Tôi sợ bạn đang giả định sai. Tôi đã đăng bài này sau khi kiểm tra mã với cả hai phiên bản khung. Xóa một thư mục không trống trong 3.5 sẽ đưa ra một ngoại lệ.
jettatore

15

Tôi đã có cùng một vấn đề dưới Delphi. Và kết quả cuối cùng là ứng dụng của riêng tôi đã khóa thư mục tôi muốn xóa. Bằng cách nào đó thư mục đã bị khóa khi tôi viết thư cho nó (một số tệp tạm thời).

Bắt 22 là, tôi đã tạo một thư mục thay đổi đơn giản cho nó trước khi xóa nó.


6
+1 Bây giờ có một cái gì đó mà msd cho Directory.Delete đã đề cập!
Ruben Bartelink

3
bất kỳ giải pháp cuối cùng với mẫu mã nguồn đầy đủ làm việc về nó?
Kiquenet

11

Tôi ngạc nhiên khi không ai nghĩ đến phương pháp không đệ quy đơn giản này, có thể xóa các thư mục chứa các tệp chỉ đọc mà không cần thay đổi thuộc tính chỉ đọc của mỗi trong số chúng.

Process.Start("cmd.exe", "/c " + @"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles"); 

(Thay đổi một chút để không kích hoạt cửa sổ cmd trong giây lát, có sẵn trên internet)


Rất vui được chia sẻ với chúng tôi nhưng bạn có tử tế khi đưa vào một chút thay đổi cần thiết để ngăn việc bắn cửa sổ cmd, thay vì nhắc chúng tôi tìm kiếm nó qua mạng không?
ThunderGr

Điều này không hoạt động. Trong tình huống tương tự khi tôi có thể xóa tệp khỏi dấu nhắc lệnh hoặc Explorer, sử dụng mã này để gọi rmdir sẽ cung cấp mã thoát 145, dịch thành "Thư mục không trống". Nó để thư mục trống nhưng vẫn ở đúng vị trí, chính xác như Directory.Delete ("", đúng)
Kevin Coulombe

@Kevin Coulombe, Humm ... Bạn có chắc là bạn đang sử dụng các công tắc / s / q không?
Piyush Soni

1
@KevinCoulombe: Vâng, nó phải là những thành phần COM. Khi tôi thử thông qua C # cũ, nó hoạt động và nó sẽ xóa thư mục cùng với các tệp bên trong (chỉ đọc hoặc không đọc).
Piyush Soni

5
Nếu bạn bắt đầu dựa vào các thành phần bên ngoài cho những gì nên có trong khung thì đó là một ý tưởng "ít hơn lý tưởng" vì nó không còn khả dụng nữa (hoặc khó khăn hơn). Nếu exe không có ở đó thì sao? Hoặc tùy chọn / thay đổi? Nếu giải pháp của Jeremy Edwards hoạt động thì nên ưu tiên IMHO
tiếng Pháp

11

Bạn có thể tái tạo lỗi bằng cách chạy:

Directory.CreateDirectory(@"C:\Temp\a\b\c\");
Process.Start(@"C:\Temp\a\b\c\");
Thread.Sleep(1000);
Directory.Delete(@"C:\Temp\a\b\c");
Directory.Delete(@"C:\Temp\a\b");
Directory.Delete(@"C:\Temp\a");

Khi cố gắng xóa thư mục 'b', nó sẽ ném IOException "Thư mục không trống". Điều đó thật ngu ngốc vì chúng tôi vừa xóa thư mục 'c'.

Theo hiểu biết của tôi, lời giải thích là thư mục 'c' được đóng dấu là đã xóa. Nhưng việc xóa vẫn chưa được cam kết trong hệ thống. Hệ thống đã trả lời công việc được thực hiện, trong khi thực tế, nó vẫn đang xử lý. Hệ thống có thể đợi trình thám hiểm tệp đã tập trung vào thư mục mẹ để thực hiện xóa.

Nếu bạn nhìn vào mã nguồn của hàm Xoá ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ), bạn sẽ thấy nó sử dụng hàm Win32Native.RemoveDirectory riêng. Hành vi không chờ đợi này được ghi chú ở đây:

Hàm RemoveDirectory đánh dấu một thư mục để xóa khi đóng. Do đó, thư mục không bị xóa cho đến khi xử lý cuối cùng đến thư mục được đóng lại.

( http://msdn.microsoft.com/en-us/l Library / windows / desktop / aa365488 ( v = vs85 ) .aspx )

Ngủ và thử lại là giải pháp. Cf giải pháp của ryascl.


8

Tôi gặp vấn đề về quyền kỳ lạ khi xóa các thư mục Hồ sơ người dùng (trong C: \ Documents and Settings) mặc dù có thể làm như vậy trong trình bao Explorer.

File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);

Nó không có nghĩa đối với tôi những gì một hoạt động "tập tin" làm trên một thư mục, nhưng tôi biết rằng nó hoạt động và đó là đủ cho tôi!


2
Vẫn không có hy vọng, khi thư mục có rất nhiều tệp và Explorer đang mở thư mục chứa các tệp đó.
xem

3

Câu trả lời này dựa trên: https://stackoverflow.com/a/1703799/184528 . Sự khác biệt với mã của tôi, là chúng tôi chỉ truy xuất lại nhiều thư mục con và tệp khi cần một cuộc gọi đến Directory. Lỗi trong lần thử đầu tiên (điều này có thể xảy ra do windows explorer nhìn vào một thư mục).

    public static void DeleteDirectory(string dir, bool secondAttempt = false)
    {
        // If this is a second try, we are going to manually 
        // delete the files and sub-directories. 
        if (secondAttempt)
        {
            // Interrupt the current thread to allow Explorer time to release a directory handle
            Thread.Sleep(0);

            // Delete any files in the directory 
            foreach (var f in Directory.GetFiles(dir, "*.*", SearchOption.TopDirectoryOnly))
                File.Delete(f);

            // Try manually recursing and deleting sub-directories 
            foreach (var d in Directory.GetDirectories(dir))
                DeleteDirectory(d);

            // Now we try to delete the current directory
            Directory.Delete(dir, false);
            return;
        }

        try
        {
            // First attempt: use the standard MSDN approach.
            // This will throw an exception a directory is open in explorer
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        }
        catch (UnauthorizedAccessException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        } 
    }

Vì vậy, làm thế nào để xóa thư mục nếu có UnauthorizedAccessException? Nó sẽ chỉ ném, một lần nữa. Và một lần nữa. Và một lần nữa ... Bởi vì mỗi lần nó sẽ đi đến catchvà gọi lại chức năng. A Thread.Sleep(0);không thay đổi quyền của bạn. Nó chỉ nên ghi lại lỗi và thất bại một cách duyên dáng, tại thời điểm đó. Và vòng lặp này sẽ tiếp tục miễn là thư mục (phụ) được mở - nó không đóng nó theo chương trình. Chúng ta đã chuẩn bị chỉ để nó làm điều này miễn là những thứ đó bị bỏ ngỏ? Có cách nào tốt hơn?
vapcguy

Nếu có, UnauthorizedAccessExceptionnó sẽ cố gắng xóa từng tệp theo cách thủ công. Vì vậy, nó tiếp tục đạt được tiến bộ bằng cách duyệt qua cấu trúc thư mục. Có, có khả năng mọi tệp và thư mục sẽ đưa ra một ngoại lệ giống nhau, nhưng điều này cũng có thể xảy ra đơn giản vì explorer đang xử lý nó (xem stackoverflow.com/a/1703799/184528 ) Tôi sẽ thay đổi "tryAgain" thành "secondTry" để làm cho nó rõ ràng hơn.
cdiggins

Để trả lời ngắn gọn hơn, nó chuyển "đúng" và thực thi một đường dẫn mã khác.
cdiggins

Phải, đã thấy chỉnh sửa của bạn, nhưng quan điểm của tôi không phải là xóa các tệp, mà là xóa thư mục. Tôi đã viết một số mã về cơ bản tôi có thể thực hiện Process.Kill()trên bất kỳ quy trình nào một tệp có thể bị khóa và xóa các tệp. Vấn đề tôi gặp phải là khi xóa một thư mục trong đó một trong những tệp đó vẫn đang mở (xem stackoverflow.com/questions/41841590/ trộm ). Vì vậy, quay trở lại vòng lặp này, bất kể nó đang làm gì, nếu nó làm lại Directory.Delete()trên thư mục đó, nó vẫn sẽ thất bại nếu xử lý đó không thể được giải phóng.
vapcguy

Và điều tương tự cũng xảy ra đối với việc UnauthorizedAccessExceptionxóa các tệp (giả sử điều này thậm chí được cho phép, bởi vì để lấy mã đó, nó không thành công Directory.Delete()) không cho phép bạn xóa thư mục một cách kỳ diệu.
vapcguy

3

Không phải là giải pháp trên làm việc tốt cho tôi. Tôi đã kết thúc bằng cách sử dụng một phiên bản chỉnh sửa của giải pháp @ryascl như dưới đây:

    /// <summary>
    /// Depth-first recursive delete, with handling for descendant 
    /// directories open in Windows Explorer.
    /// </summary>
    public static void DeleteDirectory(string path)
    {
        foreach (string directory in Directory.GetDirectories(path))
        {
            Thread.Sleep(1);
            DeleteDir(directory);
        }
        DeleteDir(path);
    }

    private static void DeleteDir(string dir)
    {
        try
        {
            Thread.Sleep(1);
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            DeleteDir(dir);
        }
        catch (UnauthorizedAccessException)
        {
            DeleteDir(dir);
        }
    }

2

Có thể bạn có một điều kiện cuộc đua trong đó một luồng hoặc quá trình khác đang thêm tệp vào thư mục:

Trình tự sẽ là:

Quy trình Deleter A:

  1. Làm trống thư mục
  2. Xóa thư mục (bây giờ trống).

Nếu ai đó thêm một tệp trong khoảng 1 & 2, thì có lẽ 2 sẽ ném ngoại lệ được liệt kê?


2

Tôi đã dành vài giờ để giải quyết vấn đề này và các ngoại lệ khác với việc xóa thư mục. Đây là giải pháp của tôi

 public static void DeleteDirectory(string target_dir)
    {
        DeleteDirectoryFiles(target_dir);
        while (Directory.Exists(target_dir))
        {
            lock (_lock)
            {
                DeleteDirectoryDirs(target_dir);
            }
        }
    }

    private static void DeleteDirectoryDirs(string target_dir)
    {
        System.Threading.Thread.Sleep(100);

        if (Directory.Exists(target_dir))
        {

            string[] dirs = Directory.GetDirectories(target_dir);

            if (dirs.Length == 0)
                Directory.Delete(target_dir, false);
            else
                foreach (string dir in dirs)
                    DeleteDirectoryDirs(dir);
        }
    }

    private static void DeleteDirectoryFiles(string target_dir)
    {
        string[] files = Directory.GetFiles(target_dir);
        string[] dirs = Directory.GetDirectories(target_dir);

        foreach (string file in files)
        {
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        }

        foreach (string dir in dirs)
        {
            DeleteDirectoryFiles(dir);
        }
    }

Mã này có độ trễ nhỏ, không quan trọng đối với ứng dụng của tôi. Nhưng hãy cẩn thận, sự chậm trễ có thể là một vấn đề cho bạn nếu bạn có nhiều thư mục con bên trong thư mục bạn muốn xóa.


8
-1 Sự chậm trễ là gì? Không có lập trình bởi sự trùng hợp xin vui lòng!
Ruben Bartelink

1
@Ruben Tôi không nói bạn sai về điều đó. Tôi chỉ nói rằng hạ thấp nó chỉ cho cái này là một hình phạt khắc nghiệt. Tôi đồng ý với bạn, tuy nhiên, 4 upvote đã không dẫn đến 4 downvote. Tôi cũng sẽ đưa ra nhận xét của bạn, nhưng tôi sẽ không đưa ra câu trả lời vì sự chậm trễ không giải thích được :)
ThunderGr

1
@RubenBartelink và những người khác: trong khi tôi không đặc biệt thích mã này (tôi đã đăng một giải pháp khác với cách tiếp cận tương tự), sự chậm trễ ở đây là hợp lý. Vấn đề rất có thể nằm ngoài tầm kiểm soát của ứng dụng; có lẽ một ứng dụng khác giải cứu FS định kỳ, do đó khóa thư mục trong khoảng thời gian ngắn. Sự chậm trễ giải quyết vấn đề, làm cho báo cáo lỗi được đếm xuống không. Ai quan tâm nếu chúng ta không có ý tưởng rõ ràng về nguyên nhân gốc rễ?
Andrey Tarantsov

1
@RubenBartelink Trên thực tế, khi bạn nghĩ về nó, không sử dụng phương pháp trì hoãn và thử lại trong quá trình xóa thư mục NTFS là một giải pháp vô trách nhiệm ở đây. Bất kỳ loại tệp truyền tải liên tục nào đều chặn việc xóa, do đó, nó chắc chắn sẽ thất bại sớm hay muộn. Và bạn không thể mong đợi tất cả các công cụ tìm kiếm, sao lưu, chống vi-rút và quản lý tệp của bên thứ ba nằm ngoài thư mục của bạn.
Andrey Tarantsov

1
@RubenBartelink Một ví dụ khác, giả sử bạn cho độ trễ 100ms và thời gian khóa cao nhất của bất kỳ phần mềm nào trên PC mục tiêu là phần mềm AV = 90ms. Nói rằng nó cũng có phần mềm sao lưu khóa các tập tin trong 70ms. Bây giờ AV khóa một tệp, ứng dụng của bạn chờ 100ms, điều này thường ổn, nhưng sau đó gặp một khóa khác vì phần mềm sao lưu bắt đầu lấy tệp ở mốc 70ms của quét AV và do đó sẽ mất thêm 40ms để phát hành tệp. Vì vậy, trong khi phần mềm AV mất nhiều thời gian hơn và 100ms của bạn thường dài hơn một trong hai ứng dụng, bạn vẫn phải tính đến khi phần mềm bắt đầu ở giữa.
vapcguy

2

Xóa thư mục đệ quy mà không xóa các tập tin chắc chắn là bất ngờ. Sửa lỗi của tôi cho điều đó:

public class IOUtils
{
    public static void DeleteDirectory(string directory)
    {
        Directory.GetFiles(directory, "*", SearchOption.AllDirectories).ForEach(File.Delete);
        Directory.Delete(directory, true);
    }
}

Tôi đã trải nghiệm các trường hợp điều này giúp, nhưng nói chung, Directory.Delete xóa các tệp trong thư mục khi xóa đệ quy, như được ghi lại trong msDN .

Thỉnh thoảng tôi cũng gặp phải hành vi bất thường này với tư cách là người dùng Windows Explorer: Đôi khi tôi không thể xóa thư mục (nó nghĩ rằng tin nhắn vô nghĩa là "truy cập bị từ chối") nhưng khi tôi đi sâu vào và xóa các mục thấp hơn thì tôi có thể xóa phần trên các mặt hàng là tốt. Vì vậy, tôi đoán mã ở trên xử lý một sự bất thường của hệ điều hành - không phải là vấn đề thư viện lớp cơ sở.


1

Thư mục hoặc một tập tin trong đó bị khóa và không thể xóa. Tìm thủ phạm đã khóa nó và xem nếu bạn có thể loại bỏ nó.


T1000 cho người dùng mở thư mục: "Bạn đã bị chấm dứt!"
vapcguy

1

Dường như có đường dẫn hoặc thư mục con được chọn trong Windows Explorer là đủ để chặn một lần thực thi Directory.Delete (đường dẫn, đúng), ném IOException như được mô tả ở trên và chết thay vì khởi động Windows Explorer vào thư mục mẹ và xử lý như hy vọng.


Đây dường như là vấn đề của tôi. Ngay khi tôi đóng Explorer và chạy lại, không có ngoại lệ. Ngay cả việc chọn cha mẹ của cha mẹ là không đủ. Tôi đã phải thực sự đóng Explorer.
Scott Marlowe

Vâng, điều này xảy ra và là một nguyên nhân. Vì vậy, bất kỳ ý tưởng làm thế nào để lập trình đối phó với nó, hoặc là câu trả lời luôn luôn để đảm bảo tất cả 1000 người dùng đã đóng thư mục đó?
vapcguy

1

Tôi đã có vấn đề này ngày hôm nay. Nó đã xảy ra bởi vì tôi đã mở windows explorer vào thư mục đang cố xóa, khiến cuộc gọi đệ quy thất bại và do đó IOException. Hãy chắc chắn rằng không có tay cầm mở vào thư mục.

Ngoài ra, MSDN rõ ràng rằng bạn không phải viết lời nhận xét của riêng mình: http://msdn.microsoft.com/en-us/l Library / fxeahc5f.aspx


1

Tôi đã gặp vấn đề tương tự với Windows Workflow Foundation trên máy chủ xây dựng với TFS2012. Trong nội bộ, quy trình làm việc được gọi là Directory.Delete () với cờ đệ quy được đặt thành đúng. Nó dường như có liên quan đến mạng trong trường hợp của chúng tôi.

Chúng tôi đã xóa một thư mục thả nhị phân trên một chia sẻ mạng trước khi tạo lại và điền lại nó với các nhị phân mới nhất. Mọi công trình khác sẽ thất bại. Khi mở thư mục thả sau khi xây dựng thất bại, thư mục trống, điều này cho biết mọi khía cạnh của lệnh gọi Directory.Delete () đều thành công trừ việc xóa thư mục thực sự.

Vấn đề dường như được gây ra bởi bản chất không đồng bộ của truyền thông tệp mạng. Máy chủ xây dựng yêu cầu máy chủ tệp xóa tất cả các tệp và máy chủ tệp báo cáo rằng nó đã có, mặc dù nó chưa hoàn thành. Sau đó, máy chủ xây dựng yêu cầu xóa thư mục và máy chủ tệp từ chối yêu cầu vì nó đã hoàn toàn xóa các tệp.

Hai giải pháp khả thi trong trường hợp của chúng tôi:

  • Xây dựng việc xóa đệ quy trong mã riêng của chúng tôi với độ trễ và xác minh giữa mỗi bước
  • Thử lại tới X lần sau IOException, trì hoãn trước khi thử lại

Phương pháp thứ hai là nhanh chóng và bẩn thỉu nhưng dường như thực hiện các mẹo.


1

Điều này là do FileChangesNotutions.

Nó xảy ra kể từ ASP.NET 2.0. Khi bạn xóa một số thư mục trong một ứng dụng, nó sẽ được khởi động lại . Bạn có thể tự nhìn thấy nó, sử dụng ASP.NET Health Monitor .

Chỉ cần thêm mã này vào web.config / configure / system.web của bạn:

<healthMonitoring enabled="true">
  <rules>
    <add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
  </rules>
</healthMonitoring>


Sau đó kiểm tra Windows Log -> Application. Chuyện gì đang xảy ra:

Khi bạn xóa thư mục, nếu có bất kỳ thư mục con nào, Delete(path, true)trước tiên hãy xóa thư mục con. Nó là đủ để FileChangesMonitor biết về việc gỡ bỏ và tắt ứng dụng của bạn. Trong khi đó thư mục chính của bạn chưa bị xóa. Đây là sự kiện từ Nhật ký:


nhập mô tả hình ảnh ở đây


Delete() đã không hoàn thành công việc của mình và vì ứng dụng đang ngừng hoạt động, nó gây ra một ngoại lệ:

nhập mô tả hình ảnh ở đây

Khi bạn không có bất kỳ thư mục con nào trong thư mục mà bạn đang xóa, Xóa () chỉ xóa tất cả các tệp và thư mục đó, ứng dụng cũng được khởi động lại, nhưng bạn không nhận được bất kỳ ngoại lệ nào , vì khởi động lại ứng dụng không làm gián đoạn bất cứ điều gì. Tuy nhiên, bạn vẫn mất tất cả các phiên trong quá trình, ứng dụng không phản hồi yêu cầu khi khởi động lại, v.v.

Gì bây giờ?

Có một số cách giải quyết và chỉnh sửa để vô hiệu hóa hành vi này, Directory Junction , Tắt FCN bằng Registry , Dừng FileChangesMonitor bằng Reflection (vì không có phương thức tiếp xúc nào) , nhưng tất cả đều không đúng, vì FCN có lý do. Nó đang chăm sóc cấu trúc ứng dụng của bạn , đây không phải là cấu trúc dữ liệu của bạn . Câu trả lời ngắn gọn là: đặt các thư mục bạn muốn xóa bên ngoài ứng dụng của mình. FileChangesMonitor sẽ không nhận được thông báo và ứng dụng của bạn sẽ không được khởi động lại mỗi lần. Bạn sẽ không có ngoại lệ. Để hiển thị chúng từ web, có hai cách:

  1. Tạo bộ điều khiển xử lý các cuộc gọi đến và sau đó phục vụ các tệp bằng cách đọc từ thư mục bên ngoài ứng dụng (bên ngoài wwwroot).

  2. Nếu dự án của bạn lớn và hiệu suất là quan trọng nhất, hãy thiết lập máy chủ web nhỏ và nhanh riêng biệt để phục vụ nội dung tĩnh. Vì vậy, bạn sẽ để lại cho IIS công việc cụ thể của mình. Nó có thể trên cùng một máy (mongoose cho Windows) hoặc máy khác (nginx cho Linux). Tin vui là bạn không phải trả thêm giấy phép microsoft để thiết lập máy chủ nội dung tĩnh trên linux.

Hi vọng điêu nay co ich.


1

Như đã đề cập ở trên, giải pháp "được chấp nhận" không thành công ở các điểm lặp lại - nhưng mọi người vẫn đánh dấu nó (???). Có một giải pháp ngắn hơn nhiều để sao chép đúng chức năng:

public static void rmdir(string target, bool recursive)
{
    string tfilename = Path.GetDirectoryName(target) +
        (target.Contains(Path.DirectorySeparatorChar.ToString()) ? Path.DirectorySeparatorChar.ToString() : string.Empty) +
        Path.GetRandomFileName();
    Directory.Move(target, tfilename);
    Directory.Delete(tfilename, recursive);
}

Tôi biết, không xử lý các trường hợp quyền được đề cập sau, nhưng với tất cả ý định và mục đích, FAR BETTER cung cấp chức năng mong đợi của thư mục gốc / stock Directory.Delete () - và với mã ít hơn rất nhiều .

Bạn có thể tiến hành xử lý một cách an toàn vì thư mục cũ sẽ hết cách ... ngay cả khi không biến mất vì 'hệ thống tệp vẫn đang bắt kịp' (hoặc bất kỳ lý do nào MS đưa ra để cung cấp chức năng bị hỏng) .

Vì lợi ích, nếu bạn biết thư mục đích của mình lớn / sâu và không muốn chờ đợi (hoặc bận tâm đến ngoại lệ), dòng cuối cùng có thể được thay thế bằng:

    ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });

Bạn vẫn an toàn để tiếp tục làm việc.


2
Việc chuyển nhượng của bạn có thể được đơn giản hóa bằng cách: string tfilename = Path.Combine (Path.GetDirectoryName (target), Path.GetRandomFileName ());
Pete

1
Tôi phải đồng ý với Pete. Mã như được viết sẽ không thêm dấu phân cách. Nó đi theo con đường của tôi \\server\C$\dirvà làm cho nó \\server\C$asf.yuw. Kết quả là tôi đã gặp lỗi trên Directory.Move()- Source and destination path must have identical roots. Move will not work across volumes. Đã hoạt động tốt khi tôi sử dụng mã EXCEPT của Pete không xử lý khi có tệp bị khóa hoặc thư mục mở - vì vậy nó không bao giờ nhận được ThreadPoollệnh.
vapcguy

THẬN TRỌNG: Câu trả lời này chỉ nên được sử dụng với đệ quy = true. Khi sai, điều này sẽ di chuyển thư mục ngay cả khi nó không trống. Đó sẽ là một lỗi; hành vi đúng trong trường hợp đó là ném một ngoại lệ, và để lại thư mục như cũ.
ToolmakerSteve

1

Vấn đề này có thể xuất hiện trên Windows khi có các tệp trong một thư mục (hoặc trong bất kỳ thư mục con nào) có độ dài đường dẫn lớn hơn 260 ký hiệu.

Trong trường hợp như vậy, bạn cần phải xóa \\\\?\C:\mydirthay vì C:\mydir. Giới hạn 260 ký hiệu bạn có thể đọc ở đây .


1

Tôi đã giải quyết bằng kỹ thuật millenary này (bạn có thể tự mình rời khỏi Thread. Ngủ

bool deleted = false;
        do
        {
            try
            {
                Directory.Delete(rutaFinal, true);                    
                deleted = true;
            }
            catch (Exception e)
            {
                string mensaje = e.Message;
                if( mensaje == "The directory is not empty.")
                Thread.Sleep(50);
            }
        } while (deleted == false);

0

Nếu thư mục hiện tại của ứng dụng của bạn (hoặc bất kỳ ứng dụng nào khác) là thư mục bạn đang cố xóa, thì đó sẽ không phải là lỗi vi phạm truy cập nhưng thư mục không trống. Hãy chắc chắn rằng đó không phải là ứng dụng của riêng bạn bằng cách thay đổi thư mục hiện tại; đồng thời, đảm bảo thư mục không mở trong một số chương trình khác (ví dụ: Word, excel, Total Commander, v.v.). Hầu hết các chương trình sẽ cd vào thư mục của tập tin cuối cùng được mở, điều này sẽ gây ra điều đó.


0

trong trường hợp tệp mạng, Directory.DeleteHelper (đệ quy: = true) có thể gây ra IOException gây ra bởi sự chậm trễ của việc xóa tệp


0

Tôi nghĩ rằng có một tệp được mở bởi một số luồng mà bạn không biết tôi có cùng một vấn đề và đã giải quyết nó bằng cách đóng tất cả các luồng mà chỉ vào thư mục tôi muốn xóa.


0

Lỗi này xảy ra nếu bất kỳ tập tin hoặc thư mục được coi là đang sử dụng. Đó là một lỗi sai. Kiểm tra xem nếu bạn có bất kỳ cửa sổ thám hiểm hoặc cửa sổ dòng lệnh nào mở cho bất kỳ thư mục nào trong cây hoặc chương trình đang sử dụng tệp trong cây đó.


0

Tôi đã giải quyết một trường hợp có thể xảy ra của sự cố đã nêu khi các phương thức không đồng bộ và được mã hóa như sau:

// delete any existing update content folder for this update
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
       await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

Với cái này:

bool exists = false;                
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
    exists = true;

// delete any existing update content folder for this update
if (exists)
    await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

Phần kết luận? Có một số khía cạnh không đồng bộ của việc loại bỏ tay cầm được sử dụng để kiểm tra sự tồn tại mà Microsoft đã không thể nói chuyện. Như thể phương thức không đồng bộ bên trong câu lệnh if có câu lệnh if hoạt động giống như câu lệnh sử dụng.


0

Bạn không phải tạo và thêm phương thức cho đệ quy hoặc xóa các tệp trong thư mục thêm. Tất cả điều này làm tự động bằng cách gọi

DirectoryInfo.Delete ();

Chi tiết tại đây .

Một cái gì đó như thế này hoạt động khá tốt:

  var directoryInfo = new DirectoryInfo("My directory path");
    // Delete all files from app data directory.

    foreach (var subDirectory in directoryInfo.GetDirectories())
    {
          subDirectory.Delete(true);// true set recursive paramter, when it is true delete sub file and sub folder with files too
    }

truyền đúng như biến để xóa phương thức, cũng sẽ xóa các tệp con và thư mục con với các tệp.


-2

Không có câu trả lời nào ở trên làm việc cho tôi. Dường như việc sử dụng ứng dụng của riêng tôiDirectoryInfo trên thư mục đích đã khiến bị khóa.

Buộc thu gom rác xuất hiện để giải quyết vấn đề, nhưng không phải ngay lập tức. Một vài nỗ lực để xóa nơi cần thiết.

Lưu ý Directory.Existsvì nó có thể biến mất sau một ngoại lệ. Tôi không biết tại sao việc xóa đối với tôi bị trì hoãn (Windows 7 SP1)

        for (int attempts = 0; attempts < 10; attempts++)
        {
            try
            {
                if (Directory.Exists(folder))
                {
                    Directory.Delete(folder, true);
                }
                return;
            }
            catch (IOException e)
            {
                GC.Collect();
                Thread.Sleep(1000);
            }
        }

        throw new Exception("Failed to remove folder.");

1
-1 Lập trình bằng sự trùng hợp. Đối tượng nào làm gì khi GC'd? Đây có phải là lời khuyên chung tốt? (Tôi tin bạn khi bạn nói rằng bạn có vấn đề và bạn đã sử dụng mã này và bạn cảm thấy hiện tại bạn không gặp vấn đề gì nhưng đó không phải là vấn đề)
Ruben Bartelink

@RubenBartelink Tôi đồng ý. Đó là một hack. Mã Voodoo làm một cái gì đó khi nó không rõ nó đang giải quyết hay làm thế nào. Tôi rất thích một giải pháp thích hợp.
Phản ứng

1
Vấn đề của tôi là bất cứ điều gì nó thêm vào và trên stackoverflow.com/a/14933880/11635 đều mang tính đầu cơ cao. Nếu tôi có thể, tôi sẽ đưa ra -1 cho trùng lặp và -1 cho đầu cơ / lập trình bởi sự trùng hợp. Sprinkling GC.Collectlà một) chỉ là Lời khuyên tồi và b) không phải là nguyên nhân chung đủ phổ biến của các thư mục bị khóa để đưa vào công đức ở đây. Chỉ cần chọn một trong những người khác và đừng gieo thêm sự nhầm lẫn trong tâm trí của những độc giả vô tội
Ruben Bartelink

3
Sử dụng GC.WaitForPendingFinalulators (); sau GC.Collect (); Điều này sẽ làm việc như mong đợi.
Heiner

Không chắc chắn, chưa được kiểm tra, nhưng có lẽ tốt hơn là làm điều gì đó với một usingtuyên bố, sau đó: using (DirectoryInfo di = new DirectoryInfo(@"c:\MyDir")) { for (int attempts = 0; attempts < 10; attempts++) { try { if (di.Exists(folder)) { Directory.Delete(folder, true); } return; } catch (IOException e) { Thread.Sleep(1000); } } }
vapcguy

-3

thêm true trong param thứ hai.

Directory.Delete(path, true);

Nó sẽ loại bỏ tất cả.


1
Directory.Delete (đường dẫn, đúng); là câu hỏi ban đầu
Pisu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.