IOException: Quá trình không thể truy cập vào tệp 'đường dẫn tệp' vì nó đang được sử dụng bởi một quy trình khác


172

Tôi có một số mã và khi nó thực thi, nó ném một IOException, nói rằng

Quá trình không thể truy cập vào tệp 'tên tệp' vì nó đang được sử dụng bởi một quy trình khác

Điều này có nghĩa là gì, và tôi có thể làm gì về nó?


1
Xem câu hỏi này để biết cách tìm quy trình khác đang sử dụng tệp.
stomy

Câu trả lời:


274

Nguyên nhân là gì?

Thông báo lỗi khá rõ ràng: bạn đang cố truy cập vào một tệp và không thể truy cập được vì một quy trình khác (hoặc thậm chí cùng quy trình) đang làm gì đó với nó (và nó không cho phép chia sẻ).

Gỡ lỗi

Nó có thể khá dễ để giải quyết (hoặc khá khó hiểu), tùy thuộc vào kịch bản cụ thể của bạn. Chúng ta hãy xem một số.

Quá trình của bạn là người duy nhất truy cập vào tệp đó
Bạn chắc chắn rằng quy trình khác là quy trình của riêng bạn. Nếu bạn biết bạn mở tệp đó trong một phần khác của chương trình, thì trước hết bạn phải kiểm tra xem bạn có đóng đúng cách xử lý tệp sau mỗi lần sử dụng không. Dưới đây là một ví dụ về mã với lỗi này:

var stream = new FileStream(path, FileAccess.Read);
var reader = new StreamReader(stream);
// Read data from this file, when I'm done I don't need it any more
File.Delete(path); // IOException: file is in use

May mắn là FileStreamthực hiện IDisposable, vì vậy thật dễ dàng để bọc tất cả mã của bạn trong một usingcâu lệnh:

using (var stream = File.Open("myfile.txt", FileMode.Open)) {
    // Use stream
}

// Here stream is not accessible and it has been closed (also if
// an exception is thrown and stack unrolled

Mô hình này cũng sẽ đảm bảo rằng các tập tin sẽ không bị bỏ ngỏ trong trường hợp ngoại lệ (đó có thể là lý do các tập tin được sử dụng: một cái gì đó đã đi sai, và không ai đóng cửa, xem bài này cho một ví dụ).

Nếu mọi thứ có vẻ ổn (bạn chắc chắn rằng bạn luôn đóng mọi tệp bạn mở, ngay cả trong trường hợp ngoại lệ) và bạn có nhiều luồng làm việc, thì bạn có hai tùy chọn: làm lại mã của mình để tuần tự truy cập tệp (không phải lúc nào cũng có thể thực hiện được và không phải lúc nào cũng muốn) hoặc áp dụng một mẫu thử lại . Đây là một mô hình khá phổ biến cho các thao tác I / O: bạn cố gắng làm điều gì đó và trong trường hợp có lỗi, bạn chờ và thử lại (ví dụ, bạn có tự hỏi tại sao, Windows Shell phải mất một thời gian để thông báo cho bạn rằng một tệp đang được sử dụng và không thể xóa?). Trong C #, nó khá dễ thực hiện (xem thêm các ví dụ tốt hơn về I / O đĩa , truy cập mạngcơ sở dữ liệu ).

private const int NumberOfRetries = 3;
private const int DelayOnRetry = 1000;

for (int i=1; i <= NumberOfRetries; ++i) {
    try {
        // Do stuff with file
        break; // When done we can break loop
    }
    catch (IOException e) when (i <= NumberOfRetries) {
        // You may check error code to filter some exceptions, not every error
        // can be recovered.
        Thread.Sleep(DelayOnRetry);
    }
}

Xin lưu ý một lỗi phổ biến chúng tôi thấy rất thường xuyên trên StackOverflow:

var stream = File.Open(path, FileOpen.Read);
var content = File.ReadAllText(path);

Trong trường hợp ReadAllText()này sẽ thất bại vì tập tin đang được sử dụng ( File.Open()trong dòng trước). Để mở tập tin trước không chỉ không cần thiết mà còn sai. Điều tương tự cũng áp dụng cho tất cả các Filechức năng mà không trả về một tay cầm đến tập tin bạn đang làm việc với: File.ReadAllText(), File.WriteAllText(), File.ReadAllLines(), File.WriteAllLines()và những người khác (như File.AppendAllXyz()chức năng) sẽ tất cả mở và đóng các tập tin bằng bản thân.

Quá trình của bạn không phải là người duy nhất truy cập tệp đó
Nếu quy trình của bạn không phải là người duy nhất truy cập tệp đó, thì tương tác có thể khó khăn hơn. Một mẫu thử lại sẽ giúp ích (nếu tệp không nên được mở bởi bất kỳ ai khác ngoài nó, thì bạn cần một tiện ích như Process Explorer để kiểm tra xem ai đang làm ).

Những cách để tránh

Khi có thể, luôn luôn sử dụng các câu lệnh để mở tệp. Như đã nói ở đoạn trước, nó sẽ chủ động giúp bạn tránh được nhiều lỗi phổ biến (xem bài đăng này để biết ví dụ về cách không sử dụng nó ).

Nếu có thể, hãy cố gắng quyết định ai sở hữu quyền truy cập vào một tệp cụ thể và tập trung quyền truy cập thông qua một vài phương pháp nổi tiếng. Ví dụ, nếu bạn có một tệp dữ liệu nơi chương trình của bạn đọc và ghi, thì bạn nên đóng hộp tất cả mã I / O bên trong một lớp. Nó sẽ giúp gỡ lỗi dễ dàng hơn (vì bạn luôn có thể đặt điểm dừng ở đó và xem ai đang làm gì) và đó cũng sẽ là điểm đồng bộ hóa (nếu cần) cho nhiều truy cập.

Đừng quên các thao tác I / O luôn có thể thất bại, một ví dụ phổ biến là:

if (File.Exists(path))
    File.Delete(path);

Nếu ai đó xóa tệp sau File.Exists()nhưng trước File.Delete()đó, thì nó sẽ ném IOExceptionvào một nơi mà bạn có thể cảm thấy an toàn.

Bất cứ khi nào có thể, hãy áp dụng mẫu thử lại và nếu bạn đang sử dụng FileSystemWatcher, hãy xem xét hành động hoãn lại (vì bạn sẽ được thông báo, nhưng một ứng dụng vẫn có thể hoạt động riêng với tệp đó).

Kịch bản nâng cao
Không phải lúc nào cũng dễ dàng, vì vậy bạn có thể cần chia sẻ quyền truy cập với người khác. Ví dụ, nếu bạn đọc từ đầu và viết đến cuối, bạn có ít nhất hai tùy chọn.

1) chia sẻ tương tự FileStreamvới các chức năng đồng bộ hóa thích hợp (vì nó không an toàn cho luồng ). Xem điều này và bài viết này cho một ví dụ.

2) sử dụng FileSharephép liệt kê để hướng dẫn HĐH cho phép các quy trình khác (hoặc các phần khác trong quy trình của riêng bạn) truy cập cùng một tệp.

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.Read))
{
}

Trong ví dụ này tôi đã chỉ ra cách mở một tệp để viết và chia sẻ để đọc; xin lưu ý rằng khi đọc và viết chồng chéo, nó dẫn đến dữ liệu không xác định hoặc không hợp lệ. Đó là một tình huống phải được xử lý khi đọc. Cũng lưu ý rằng điều này không làm cho quyền truy cập vào streamluồng an toàn, vì vậy đối tượng này không thể được chia sẻ với nhiều luồng trừ khi quyền truy cập được đồng bộ hóa bằng cách nào đó (xem các liên kết trước đó). Các tùy chọn chia sẻ khác có sẵn và chúng mở ra các kịch bản phức tạp hơn. Vui lòng tham khảo MSDN để biết thêm chi tiết.

Nói chung, các quy trình N có thể đọc từ cùng một tệp nhưng chỉ một người nên viết, trong một kịch bản được kiểm soát, bạn thậm chí có thể kích hoạt các bài viết đồng thời nhưng điều này không thể được khái quát trong một vài đoạn văn bản trong câu trả lời này.

Có thể mở khóa một tập tin được sử dụng bởi một quá trình khác? Nó không phải lúc nào cũng an toàn và không dễ dàng nhưng có, nó có thể .


Tôi không biết có vấn đề gì với mã của mình, tôi sử dụng các khối, nhưng vẫn có lỗi cho biết tệp đang được sử dụng khi tôi cố xóa nó.
Jamshaid Kamran

Không, thực ra tôi có một điều khiển hẹn giờ làm điều đó, bên cạnh bộ đếm thời gian, nếu tôi gọi lại chức năng thì nó sẽ ném ra một ngoại lệ. về cơ bản tôi đang giải mã một tập tin thành một tập tin văn bản khác, sau đó xóa tập tin vừa tạo ,, nó ném ngoại lệ vào việc xóa!
Jamshaid Kamran

3
@ مشیدکامران Tại sao tạo một tệp có nội dung bạn có trong mã của mình, sau đó xóa nó? Có vẻ kỳ lạ để tạo tập tin ở vị trí đầu tiên, sau đó. Vì bạn không đăng mã, chúng tôi không biết bạn đang làm gì. Nhưng khi bạn tạo tập tin của mình, nếu bạn làm điều đó với File.Create(path), bạn nên thêm .Close()vào cuối của nó trước khi bạn viết nó. Có những cạm bẫy như thế, ngoài các usingcâu lệnh để ghi các tệp, sau đó xóa chúng. Bạn nên đăng mã trong câu hỏi của bạn về cách bạn đang tạo và xóa tệp của mình. Nhưng có lẽ rơi vào phù hợp với một cái gì đó được đề cập ở trên.
vapcguy

Mã của tôi sử dụng Directory.SetCreationTimeUTC()nhưng không thành công khi File Explorer đang mở, tuyên bố thư mục đang được truy cập bởi một quy trình khác. Tôi nên xử lý tình huống này như thế nào?
Kyle Delaney

1
@KyleDelaney Tôi muốn nói rằng bạn cần đợi cho đến khi thư mục được đóng lại, nếu không phải là vài giây thì mọi thứ sẽ nhanh chóng trở nên phức tạp (giữ một hàng đợi nền với các hoạt động đang chờ xử lý? Trình theo dõi hệ thống tệp? Thăm dò?) gửi câu hỏi với nhiều chi tiết hơn cho câu trả lời đặc biệt
Adriano Repetti

28

Sử dụng FileShare đã khắc phục sự cố mở tệp của tôi ngay cả khi nó được mở bởi một quy trình khác.

using (var stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
}

9

Có một vấn đề trong khi tải lên một hình ảnh và không thể xóa nó và tìm thấy một giải pháp. gl hf

//C# .NET
var image = Image.FromFile(filePath);

image.Dispose(); // this removes all resources

//later...

File.Delete(filePath); //now works

2
Nếu bạn đang xóa một tập tin, bạn cần loại bỏ đối tượng hình ảnh trước.
shazia

1
Đẹp, tôi tìm giải pháp này. Tôi cũng gặp vấn đề với chức năng Image.FromFile.
Scion

1
@thescion :) np
Hudson

1
Điều này làm việc tuyệt vời cho tôi và giải quyết vấn đề chính xác của tôi. Tôi muốn xử lý một thư mục các tệp Tiff, chuyển đổi chúng thành các luồng byte [] và gửi đến một dịch vụ, sau đó di chuyển thư mục của các tệp Tiff sang thư mục lưu trữ "Đã xử lý". Image.FromFile đặt khóa trên tệp Tiff và không giải phóng kịp thời, vì vậy khi tôi di chuyển tệp Tiff và chứa thư mục, tôi sẽ gặp lỗi "đang được sử dụng bởi một quy trình khác", vì các khóa vẫn còn tại chỗ Thực hiện .Release ngay sau khi nhận được các byte của tệp Tiff đã khắc phục hoàn toàn sự cố tệp bị khóa này.
Nhà phát

4

Tôi đã gặp lỗi này vì tôi đang thực hiện File.Move đến một đường dẫn tệp không có tên tệp, cần chỉ định đường dẫn đầy đủ ở đích.


Và không chỉ không có tên tệp. Tên tệp (đích) bất hợp pháp - trong trường hợp của tôi "... \ file." - sẽ đưa ra lỗi tương tự ngu ngốc này và chỉ cho bạn sai hướng trong nửa ngày!
Nick Westgate

3

Lỗi cho thấy một quá trình khác đang cố gắng truy cập tệp. Có thể bạn hoặc người khác mở nó trong khi bạn đang cố viết cho nó. "Đọc" hoặc "Sao chép" thường không gây ra điều này, nhưng viết thư cho nó hoặc gọi xóa trên đó.

Có một số điều cơ bản để tránh điều này, như các câu trả lời khác đã đề cập:

  1. Trong các FileStreamhoạt động, đặt nó trong một usingkhối với một FileShare.ReadWritechế độ truy cập.

    Ví dụ:

    using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
    {
    }
    

    Lưu ý rằng FileAccess.ReadWritekhông thể nếu bạn sử dụng FileMode.Append.

  2. Tôi đã chạy qua vấn đề này khi tôi đang sử dụng một luồng đầu vào để thực hiện File.SaveAskhi tập tin được sử dụng. Trong trường hợp của tôi, tôi đã tìm thấy, tôi thực sự không cần phải lưu nó trở lại hệ thống tệp, vì vậy cuối cùng tôi đã gỡ bỏ nó, nhưng tôi có thể đã thử tạo FileStream trong một usingcâu lệnh FileAccess.ReadWrite, giống như mã ở trên.

  3. Lưu dữ liệu của bạn dưới dạng một tệp khác và quay lại xóa dữ liệu cũ khi phát hiện thấy nó không còn được sử dụng, sau đó đổi tên dữ liệu đã lưu thành công thành tên của tệp gốc là một tùy chọn. Cách bạn kiểm tra tệp đang sử dụng được thực hiện thông qua

    List<Process> lstProcs = ProcessHandler.WhoIsLocking(file);

    trong mã của tôi dưới đây và có thể được thực hiện trong một dịch vụ Windows, trên một vòng lặp, nếu bạn có một tệp cụ thể bạn muốn xem và xóa thường xuyên khi bạn muốn thay thế nó. Nếu bạn không luôn có cùng một tệp, một tệp văn bản hoặc bảng cơ sở dữ liệu có thể được cập nhật rằng dịch vụ luôn kiểm tra tên tệp và sau đó thực hiện kiểm tra các quy trình và sau đó thực hiện quy trình giết và xóa nó, như tôi mô tả trong tùy chọn tiếp theo. Lưu ý rằng bạn sẽ cần một tên người dùng và mật khẩu tài khoản có đặc quyền Quản trị viên trên máy tính đã cho, tất nhiên, để thực hiện xóa và kết thúc các quy trình.

  4. Khi bạn không biết liệu một tệp sẽ được sử dụng khi bạn đang cố lưu nó, bạn có thể đóng tất cả các quy trình có thể đang sử dụng, như Word, nếu đó là tài liệu Word, trước khi lưu.

    Nếu nó là địa phương, bạn có thể làm điều này:

    ProcessHandler.localProcessKill("winword.exe");

    Nếu nó ở xa, bạn có thể làm điều này:

    ProcessHandler.remoteProcessKill(computerName, txtUserName, txtPassword, "winword.exe");

    ở đâu txtUserNamedưới dạng DOMAIN\user.

  5. Giả sử bạn không biết tên quy trình đang khóa tệp. Sau đó, bạn có thể làm điều này:

    List<Process> lstProcs = new List<Process>();
    lstProcs = ProcessHandler.WhoIsLocking(file);
    
    foreach (Process p in lstProcs)
    {
        if (p.MachineName == ".")
            ProcessHandler.localProcessKill(p.ProcessName);
        else
            ProcessHandler.remoteProcessKill(p.MachineName, txtUserName, txtPassword, p.ProcessName);
    }
    

    Lưu ý rằng filephải là đường dẫn UNC: \\computer\share\yourdoc.docxđể cho Processđể tìm ra những gì máy tính nó vào và p.MachineNamecó giá trị.

    Dưới đây là lớp mà các hàm này sử dụng, yêu cầu thêm một tham chiếu đến System.Management. Mã ban đầu được viết bởi Eric J . :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Management;
    
    namespace MyProject
    {
        public static class ProcessHandler
        {
            [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;
            }
    
            public static void remoteProcessKill(string computerName, string userName, string pword, string processName)
            {
                var connectoptions = new ConnectionOptions();
                connectoptions.Username = 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();
                    }
                }            
            }
    
            public static void localProcessKill(string processName)
            {
                foreach (Process p in Process.GetProcessesByName(processName))
                {
                    p.Kill();
                }
            }
    
            [DllImport("kernel32.dll")]
            public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);
    
            public const int MOVEFILE_DELAY_UNTIL_REBOOT = 0x4;
    
        }
    }
    

2

Như các câu trả lời khác trong chủ đề này đã chỉ ra, để khắc phục lỗi này, bạn cần kiểm tra cẩn thận mã, để hiểu nơi tệp bị khóa.

Trong trường hợp của tôi, tôi đã gửi tệp dưới dạng tệp đính kèm email trước khi thực hiện thao tác di chuyển.

Vì vậy, tệp đã bị khóa trong vài giây cho đến khi máy khách SMTP hoàn tất việc gửi email.

Giải pháp tôi áp dụng là di chuyển tệp trước, sau đó gửi email. Điều này giải quyết các vấn đề đối với tôi.

Một giải pháp khả thi khác, như Hudson đã chỉ ra trước đó, sẽ là vứt bỏ đồ vật sau khi sử dụng.

public static SendEmail()
{
           MailMessage mMailMessage = new MailMessage();
           //setup other email stuff

            if (File.Exists(attachmentPath))
            {
                Attachment attachment = new Attachment(attachmentPath);
                mMailMessage.Attachments.Add(attachment);
                attachment.Dispose(); //disposing the Attachment object
            }
} 

Nếu một tệp đang được sử dụng File.Move()sẽ không hoạt động và gây ra lỗi tương tự. Nếu chỉ thêm một tệp vào e-mail, tôi không nghĩ nó bị lỗi khi sử dụng trong quá trình Attachments.Add()hoạt động vì đây chỉ là một thao tác sao chép. Nếu vì lý do nào đó, bạn có thể sao chép nó vào thư mục Temp, đính kèm bản sao và xóa tệp đã sao chép sau đó. Nhưng tôi không nghĩ, nếu OP muốn sửa đổi một tệp và sử dụng tệp đó, thì loại giải pháp này (mà bạn không hiển thị mã, chỉ phần đính kèm) sẽ hoạt động. .Dispose()luôn luôn là một ý tưởng tốt, nhưng không liên quan ở đây trừ khi tập tin được mở trong một op trước.
vapcguy

1

Tôi đã có kịch bản sau đây gây ra lỗi tương tự:

  • Tải tập tin lên máy chủ
  • Sau đó loại bỏ các tập tin cũ sau khi chúng được tải lên

Hầu hết các tệp có kích thước nhỏ, tuy nhiên, một số tệp lớn và do đó cố gắng xóa những tệp đó dẫn đến lỗi không thể truy cập tệp .

Thật không dễ tìm, tuy nhiên, giải pháp đơn giản như Chờ đợi "để tác vụ hoàn thành thực thi":

using (var wc = new WebClient())
{
   var tskResult = wc.UploadFileTaskAsync(_address, _fileName);
   tskResult.Wait(); 
}

-1

Mã dưới đây của tôi giải quyết vấn đề này, nhưng tôi đề nghị Trước hết bạn cần hiểu nguyên nhân gây ra sự cố này và thử giải pháp mà bạn có thể tìm thấy bằng cách thay đổi mã

Tôi có thể đưa ra một cách khác để giải quyết vấn đề này nhưng giải pháp tốt hơn là kiểm tra cấu trúc mã hóa của bạn và cố gắng phân tích điều gì xảy ra, nếu bạn không tìm thấy bất kỳ giải pháp nào thì bạn có thể đi với mã này bên dưới

try{
Start:
///Put your file access code here


}catch (Exception ex)
 {
//by anyway you need to handle this error with below code
   if (ex.Message.StartsWith("The process cannot access the file"))
    {
         //Wait for 5 seconds to free that file and then start execution again
         Thread.Sleep(5000);
         goto Start;
    }
 }

1
Một vài vấn đề với mã này: 1) nếu bạn cần gọi GC.*()thì có lẽ bạn có vấn đề khác với mã của mình. 2) Tin nhắn được bản địa hóa và dễ vỡ , thay vào đó hãy sử dụng HRESULT. 3) Bạn có thể muốn ngủ với Task.Delay()(và mười giây bằng cách nào đó quá mức trong nhiều trường hợp). 4) Bạn không có điều kiện thoát: mã này có thể treo forver. 5) Bạn chắc chắn không cần gotoở đây. 6) Để bắt Exceptionthường là một ý tưởng tồi, trong trường hợp này cũng bởi vì ... 6) Nếu có bất cứ điều gì khác xảy ra thì bạn đang nuốt lỗi.
Adriano Repetti

@AdrianoRepetti Nhận xét đầu tiên của tôi cho biết không sử dụng mã này, hãy thử tìm giải pháp khác, đây sẽ là tùy chọn cuối cùng và dù sao đi nữa, nếu lỗi này xảy ra, mã sẽ bị dừng nhưng nếu bạn đang xử lý thì hệ thống lỗi này sẽ đợi để giải phóng tệp và sau đó nó sẽ bắt đầu làm việc và tôi không gặp phải các vấn đề khác với GC. * trong khi sử dụng mã này. Tôi đã có hệ thống làm việc với mã này vì vậy tôi đã đăng có thể hữu ích cho ai đó.
Tro

Tôi đã nói rằng đừng sử dụng mã này bao giờ (vì những điểm tôi đã đề cập ở trên) và tôi sẽ không xem xét việc này hoạt động trong một hệ thống prod mà đó chỉ là POV của tôi. Hãy đồng ý!
Adriano Repetti

1) Tôi đã sử dụng dịch vụ windows nơi tôi đã sử dụng dịch vụ này và tôi đã sử dụng GC. * Cho đến lúc này tôi không gặp phải bất kỳ vấn đề nào với điều này2) yeah HRESULT có thể là lựa chọn tốt hơn về mặt tiêu chuẩn mã hóa 3) Tùy thuộc vào tình huống bạn có thể chỉnh sửa đến 5 giây 4) dù sao thì tốt hơn là hệ thống chờ đôi khi giải phóng tài nguyên thay vì dừng hệ thống có lỗi 5) vâng tôi đồng ý với bạn xử lý ngoại lệ không phải lúc nào cũng tốt nhưng nếu đoạn mã của bạn nhỏ và bạn biết Ở đây tôi có thể xử lý ngoại lệ thì giải pháp này là một lựa chọn cho bạn.
Tro

Xem thêm: docs.microsoft.com/en-us/archive/bloss/ricom/ . Trường hợp CHỈ (và tôi nhấn mạnh CHỈ) tôi cần sử dụng GC.Collect()là khi xử lý một số đối tượng COM.
Adriano Repetti
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.