IOException: กระบวนการไม่สามารถเข้าถึงไฟล์ 'เส้นทางไฟล์' ได้เนื่องจากกำลังถูกใช้โดยกระบวนการอื่น


172

ฉันมีโค้ดบางส่วนและเมื่อมันประมวลผลมันจะพ่น a IOExceptionโดยบอกว่า

กระบวนการไม่สามารถเข้าถึงไฟล์ 'ชื่อไฟล์' ได้เนื่องจากกำลังถูกใช้โดยกระบวนการอื่น

สิ่งนี้หมายความว่าอะไรและฉันจะทำอย่างไรกับเรื่องนี้?


1
ดูคำถามนี้สำหรับวิธีค้นหากระบวนการอื่นที่กำลังใช้ไฟล์
stomy

คำตอบ:


274

สาเหตุคืออะไร?

ข้อความแสดงข้อผิดพลาดค่อนข้างชัดเจน: คุณกำลังพยายามเข้าถึงไฟล์และไม่สามารถเข้าถึงได้เนื่องจากกระบวนการอื่น (หรือแม้แต่กระบวนการเดียวกัน) กำลังทำบางสิ่งกับมัน (และไม่อนุญาตให้มีการแบ่งปันใด ๆ )

แก้จุดบกพร่อง

อาจเป็นเรื่องง่ายในการแก้ (หรือยากที่จะเข้าใจ) ขึ้นอยู่กับสถานการณ์เฉพาะของคุณ มาดูกันบ้าง

กระบวนการของคุณเป็นเพียงการเข้าถึงไฟล์นั้น
คุณมั่นใจว่ากระบวนการอื่นเป็นกระบวนการของคุณเอง หากคุณรู้ว่าคุณเปิดไฟล์นั้นในส่วนอื่นของโปรแกรมของคุณก่อนอื่นคุณต้องตรวจสอบว่าคุณปิดตัวจัดการไฟล์อย่างถูกต้องหลังจากใช้งานแต่ละครั้ง นี่คือตัวอย่างของรหัสที่มีข้อบกพร่องนี้:

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

โชคดีที่FileStreamใช้งานIDisposableดังนั้นมันง่ายที่จะห่อโค้ดทั้งหมดของคุณไว้ในusingคำสั่ง:

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

รูปแบบนี้ยังจะช่วยให้มั่นใจว่าไฟล์จะไม่ถูกเปิดทิ้งไว้ในกรณีที่มีข้อยกเว้น (มันอาจจะเป็นเหตุผลไฟล์ที่อยู่ในการใช้งาน: สิ่งที่ผิดพลาดและไม่มีใครปิดมันดูโพสต์นี้สำหรับตัวอย่าง)

หากทุกอย่างดูดี (คุณแน่ใจว่าคุณปิดทุกไฟล์ที่คุณเปิดอยู่เสมอแม้ในกรณีที่มีข้อยกเว้น) และคุณมีหลายเธรดการทำงานคุณมีสองตัวเลือก: ทำใหม่รหัสของคุณเพื่อทำให้การเข้าใช้ไฟล์เป็นอนุกรม อยาก) หรือใช้รูปแบบลองใหม่อีกครั้ง เป็นรูปแบบที่ใช้กันทั่วไปสำหรับการดำเนินการ I / O: คุณพยายามทำบางสิ่งบางอย่างและในกรณีที่เกิดข้อผิดพลาดคุณรอและลองอีกครั้ง (คุณถามตัวเองว่าทำไมตัวอย่างเช่น Windows Shell ใช้เวลาสักครู่เพื่อแจ้งให้คุณทราบว่า และไม่สามารถลบได้?) ใน C # ก็สวยง่ายต่อการใช้ (ดูตัวอย่างยังดีขึ้นเกี่ยวกับดิสก์ของ I / O , การสร้างเครือข่ายและการเข้าถึงฐานข้อมูล )

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

โปรดทราบข้อผิดพลาดทั่วไปที่เราพบบ่อยใน StackOverflow:

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

ในกรณีนี้ReadAllText()จะล้มเหลวเนื่องจากไฟล์มีการใช้งาน ( File.Open()ในบรรทัดก่อน) หากต้องการเปิดไฟล์ล่วงหน้าไม่เพียง แต่ไม่จำเป็นเท่านั้น แต่ยังผิดด้วย เช่นเดียวกับทุกFileฟังก์ชั่นที่ไม่ได้กลับมาเป็นที่จับไฟล์ที่คุณกำลังทำงานกับ: File.ReadAllText(), File.WriteAllText(), File.ReadAllLines(), File.WriteAllLines()และอื่น ๆ (เช่นFile.AppendAllXyz()ฟังก์ชั่น) ทั้งหมดจะเปิดและปิดแฟ้มด้วยตัวเอง

กระบวนการของคุณไม่ใช่เพียงการเข้าถึงไฟล์นั้น
หากกระบวนการของคุณไม่ใช่เพียงการเข้าถึงไฟล์นั้นการโต้ตอบอาจทำได้ยากขึ้น รูปแบบลองใหม่อีกครั้งจะช่วยให้ (ถ้าไฟล์ไม่ควรจะเปิดโดยคนอื่น แต่มันก็เป็นแล้วคุณจะต้องสาธารณูปโภคเช่น Process Explorer เพื่อตรวจสอบผู้ที่จะทำสิ่งที่ )

วิธีการหลีกเลี่ยง

เมื่อบังคับให้ใช้โดยใช้งบในการเปิดไฟล์ ดังที่ได้กล่าวไว้ในย่อหน้าก่อนหน้ามันจะช่วยให้คุณหลีกเลี่ยงข้อผิดพลาดทั่วไปมากมาย (ดูโพสต์นี้เพื่อดูตัวอย่างว่าจะไม่ใช้มันอย่างไร )

หากเป็นไปได้ให้พยายามตัดสินใจว่าใครเป็นเจ้าของการเข้าถึงไฟล์เฉพาะและรวบรวมการเข้าถึงจากศูนย์กลางด้วยวิธีที่รู้จักกันดี ตัวอย่างเช่นหากคุณมีไฟล์ข้อมูลที่โปรแกรมของคุณอ่านและเขียนคุณควรใส่รหัส I / O ทั้งหมดไว้ในคลาสเดียว มันจะทำให้การดีบักง่ายขึ้น (เพราะคุณสามารถใส่เบรกพอยต์ที่นั่นและดูว่าใครกำลังทำอะไรอยู่) และมันจะเป็นจุดประสาน (ถ้าจำเป็น) สำหรับการเข้าถึงหลายจุด

อย่าลืมการดำเนินการ I / O สามารถล้มเหลวได้เสมอตัวอย่างทั่วไปคือ:

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

หากใครบางคนลบไฟล์หลังจากFile.Exists()แต่ก่อนFile.Delete()แล้วมันจะโยนIOExceptionในสถานที่ที่คุณอาจรู้สึกผิดอย่างปลอดภัย

เมื่อใดก็ตามที่เป็นไปได้ให้ใช้รูปแบบการลองใหม่และหากคุณกำลังใช้อยู่ให้ลองFileSystemWatcherดำเนินการเลื่อน (เนื่องจากคุณจะได้รับแจ้ง แต่แอปพลิเคชันอาจยังคงทำงานเฉพาะกับไฟล์นั้น)

สถานการณ์ขั้นสูง
ไม่ใช่เรื่องง่ายเสมอไปดังนั้นคุณอาจต้องแบ่งปันการเข้าถึงกับบุคคลอื่น ตัวอย่างเช่นหากคุณกำลังอ่านตั้งแต่ต้นและเขียนจนจบคุณมีตัวเลือกอย่างน้อยสองตัว

1) แบ่งปันสิ่งเดียวกันFileStreamกับฟังก์ชั่นการซิงโครไนซ์ที่เหมาะสม (เพราะไม่ปลอดภัยต่อเธรด ) ดูตัวอย่างนี้และโพสต์นี้สำหรับตัวอย่าง

2) ใช้การFileShareแจงนับเพื่อสั่งให้ระบบปฏิบัติการอนุญาตให้กระบวนการอื่น ๆ (หรือส่วนอื่น ๆ ของกระบวนการของคุณ) เข้าถึงไฟล์เดียวกันพร้อมกัน

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

ในตัวอย่างนี้ฉันแสดงให้เห็นถึงวิธีการเปิดไฟล์สำหรับการเขียนและแบ่งปันสำหรับการอ่าน; โปรดทราบว่าเมื่อการอ่านและการเขียนทับซ้อนกันจะส่งผลให้ข้อมูลไม่ได้กำหนดหรือไม่ถูกต้อง เป็นสถานการณ์ที่ต้องจัดการเมื่ออ่าน นอกจากนี้โปรดทราบว่าการทำเช่นนี้ไม่ได้ทำให้สามารถเข้าถึงstreamthread-safe ได้ดังนั้นวัตถุนี้ไม่สามารถแชร์กับหลาย ๆ เธรดได้เว้นแต่ว่าการซิงโครไนซ์จะเข้าถึงอย่างใดอย่างหนึ่ง (ดูลิงค์ก่อนหน้า) มีตัวเลือกการแชร์อื่น ๆ และเปิดสถานการณ์ที่ซับซ้อนมากขึ้น โปรดอ้างอิงMSDNสำหรับรายละเอียดเพิ่มเติม

โดยทั่วไปกระบวนการNสามารถอ่านจากไฟล์เดียวกันทั้งหมดพร้อมกัน แต่ควรเขียนเพียงหนึ่งเดียวในสถานการณ์จำลองที่ควบคุมคุณอาจเปิดใช้งานการเขียนพร้อมกันได้ แต่สิ่งนี้ไม่สามารถสรุปในย่อหน้าข้อความในคำตอบนี้ได้

เป็นไปได้หรือไม่ที่จะปลดล็อกไฟล์ที่ใช้โดยกระบวนการอื่น? มันไม่ปลอดภัยเสมอและไม่ง่าย แต่ใช่มันเป็นไปได้


ฉันไม่ทราบว่ารหัสของฉันผิดปกติฉันใช้การใช้บล็อก แต่ยังมีข้อผิดพลาดที่บอกว่าไฟล์นั้นถูกใช้งานเมื่อฉันพยายามลบ
Jamshaid Kamran

ไม่จริงฉันมีการควบคุมการจับเวลาทำเช่นนั้นข้างจับเวลาถ้าฉันเรียกใช้ฟังก์ชั่นอีกครั้งมันจะโยนข้อยกเว้น โดยทั่วไปฉันกำลังถอดรหัสไฟล์เป็นไฟล์ข้อความอื่นหลังจากนั้นลบไฟล์ที่สร้างขึ้นใหม่ซึ่งจะทำให้เกิดข้อยกเว้นในการลบ!
Jamshaid Kamran

3
@ جمشیدکامرانเหตุใดจึงสร้างไฟล์ที่มีเนื้อหาที่คุณมีในรหัสของคุณแล้วลบมัน? ดูเหมือนว่าแปลกที่จะสร้างไฟล์ในตอนแรกแล้ว เนื่องจากคุณไม่ได้โพสต์รหัสเราไม่ทราบว่าคุณกำลังทำอะไร แต่เมื่อคุณสร้างไฟล์ถ้าคุณทำFile.Create(path)คุณควรเพิ่ม.Close()ที่ส่วนท้ายของไฟล์ก่อนที่จะเขียนลงไป มีข้อผิดพลาดเช่นนั้นนอกเหนือจากusingคำสั่งสำหรับการเขียนไฟล์แล้วลบหลังจากพวกเขา คุณควรโพสต์รหัสในคำถามของคุณว่าคุณสร้างและลบไฟล์อย่างไร แต่อาจสอดคล้องกับสิ่งที่กล่าวถึงข้างต้น
vapcguy

รหัสของฉันใช้Directory.SetCreationTimeUTC()แต่มันล้มเหลวเมื่อเปิด File Explorer โดยอ้างว่ามีการเข้าถึงไดเรกทอรีโดยกระบวนการอื่น ฉันควรจัดการกับสถานการณ์นี้อย่างไร
Kyle Delaney

1
@ KyleDelaney ฉันจะบอกว่าคุณต้องรอจนกว่าโฟลเดอร์จะถูกปิดถ้ามันไม่กี่วินาทีแล้วทุกอย่างจะกลายเป็นซับซ้อน (เก็บคิวพื้นหลังด้วยการดำเนินการที่รอดำเนินการหรือไม่เฝ้าดูระบบไฟล์? Polling?) คุณอาจต้องการ โพสต์คำถามพร้อมรายละเอียดเพิ่มเติมสำหรับคำตอบแบบเฉพาะกิจ
Adriano Repetti

29

การใช้FileShareแก้ไขปัญหาการเปิดไฟล์ของฉันแม้ว่ากระบวนการอื่นจะเปิดขึ้น

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

9

พบปัญหาขณะอัปโหลดภาพและไม่สามารถลบได้และพบวิธีแก้ไข gl hf

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

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

//later...

File.Delete(filePath); //now works

2
หากคุณกำลังลบไฟล์คุณจะต้องกำจัดวัตถุภาพก่อน
Shazia

1
ดีฉันมองหาวิธีแก้ปัญหานี้ ฉันยังมีปัญหากับฟังก์ชั่น Image.FromFile
การปลูกถ่าย

1
@thescion :) np
ฮัดสัน

1
สิ่งนี้ทำงานได้ดีสำหรับฉันและแก้ไขปัญหาที่แน่นอนของฉัน ฉันต้องการประมวลผลโฟลเดอร์ของไฟล์ Tiff แปลงเป็นสตรีม [] และส่งไปยังบริการแล้วย้ายโฟลเดอร์ของไฟล์ Tiff ไปยังโฟลเดอร์เก็บถาวร "ประมวลผล" Image.FromFile วางล็อคไฟล์ Tiff และไม่ปล่อยออกมาทันเวลาดังนั้นเมื่อฉันย้ายไฟล์ Tiff และมีโฟลเดอร์ฉันจะได้รับข้อผิดพลาด "กำลังถูกใช้โดยกระบวนการอื่น" เนื่องจากล็อคยังคงอยู่ ในสถานที่. ทำ .Release ทันทีหลังจากรับไบต์ของไฟล์ Tiff แก้ไขปัญหาไฟล์ที่ถูกล็อคทั้งหมด
Developer63

4

ฉันได้รับข้อผิดพลาดนี้เพราะฉันกำลังทำ File.Move ไปยังเส้นทางของไฟล์ที่ไม่มีชื่อไฟล์จำเป็นต้องระบุเส้นทางแบบเต็มในปลายทาง


และไม่เพียงแค่ไม่มีชื่อไฟล์เช่นกัน ชื่อไฟล์ (ปลายทาง) ที่ผิดกฎหมาย - ในกรณีของฉัน "... \ file." - จะให้ข้อผิดพลาดโง่เดียวกันนี้และชี้คุณในทิศทางที่ผิดสำหรับครึ่งวัน!
Nick Westgate

3

ข้อผิดพลาดระบุว่ากระบวนการอื่นกำลังพยายามเข้าถึงไฟล์ บางทีคุณหรือคนอื่นเปิดไว้ในขณะที่คุณพยายามเขียนถึงมัน "อ่าน" หรือ "คัดลอก" มักจะไม่ก่อให้เกิดสิ่งนี้ แต่การเขียนไปที่มันหรือโทรลบที่มันจะ

มีสิ่งพื้นฐานที่ต้องหลีกเลี่ยงสิ่งนี้ตามที่คำตอบอื่น ๆ ได้กล่าวไว้:

  1. ในFileStreamการดำเนินการวางไว้ในusingบล็อกด้วยFileShare.ReadWriteโหมดการเข้าถึง

    ตัวอย่างเช่น:

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

    ทราบว่าเป็นไปไม่ได้ถ้าคุณใช้FileAccess.ReadWriteFileMode.Append

  2. ฉันพบปัญหานี้เมื่อฉันใช้สตรีมอินพุตเพื่อทำFile.SaveAsไฟล์เมื่อใช้งานอยู่ ในกรณีของฉันฉันพบว่าฉันไม่จำเป็นต้องบันทึกมันกลับไปที่ระบบไฟล์เลยดังนั้นฉันจึงลงเอยด้วยการลบสิ่งนั้น แต่ฉันอาจลองสร้าง FileStream ในusingคำสั่งด้วยFileAccess.ReadWriteเหมือนรหัส ข้างบน.

  3. บันทึกข้อมูลของคุณเป็นไฟล์อื่นและกลับไปลบไฟล์เก่าเมื่อพบว่าไม่มีการใช้งานอีกต่อไปจากนั้นเปลี่ยนชื่อไฟล์ที่บันทึกไว้เป็นชื่อของไฟล์เดิมเป็นตัวเลือก วิธีที่คุณทดสอบไฟล์ที่กำลังใช้งานนั้นทำได้โดยผ่าน

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

    บรรทัดในรหัสของฉันด้านล่างและสามารถทำได้ในบริการ Windows ในวงถ้าคุณมีไฟล์เฉพาะที่คุณต้องการดูและลบเป็นประจำเมื่อคุณต้องการแทนที่ หากคุณไม่มีไฟล์เดียวกันอยู่เสมอไฟล์ข้อความหรือตารางฐานข้อมูลสามารถอัปเดตได้ว่าบริการจะตรวจสอบชื่อไฟล์เสมอจากนั้นทำการตรวจสอบกระบวนการและดำเนินการตามขั้นตอนเพื่อฆ่าและลบตามที่ฉันอธิบาย ในตัวเลือกถัดไป โปรดทราบว่าคุณจะต้องมีชื่อผู้ใช้และรหัสผ่านของบัญชีที่มีสิทธิ์ของผู้ดูแลระบบในคอมพิวเตอร์ที่กำหนดไว้เพื่อดำเนินการลบและสิ้นสุดกระบวนการ

  4. เมื่อคุณไม่ทราบว่าไฟล์จะถูกใช้เมื่อคุณพยายามบันทึกหรือไม่คุณสามารถปิดกระบวนการทั้งหมดที่สามารถใช้งานได้เช่น Word หากเป็นเอกสาร Word ก่อนการบันทึก

    หากเป็นท้องถิ่นคุณสามารถทำสิ่งนี้ได้:

    ProcessHandler.localProcessKill("winword.exe");

    หากเป็นรีโมทคุณสามารถทำสิ่งนี้ได้:

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

    ที่อยู่ในรูปแบบของ txtUserNameDOMAIN\user

  5. สมมติว่าคุณไม่รู้ชื่อกระบวนการที่กำลังล็อคไฟล์ จากนั้นคุณสามารถทำสิ่งนี้:

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

    โปรดทราบว่าfileจะต้องเป็นเส้นทาง UNC: \\computer\share\yourdoc.docxเพื่อให้Processสามารถทราบได้ว่าคอมพิวเตอร์นั้นอยู่ในสถานะใดและp.MachineNameถูกต้อง

    System.Managementด้านล่างเป็นชั้นฟังก์ชั่นเหล่านี้ใช้ซึ่งจะต้องมีการเพิ่มการอ้างอิงถึง รหัสเดิมเขียนโดย 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

ตามที่คำตอบอื่น ๆ ในเธรดนี้ได้ชี้ให้เห็นเพื่อแก้ไขข้อผิดพลาดนี้คุณต้องตรวจสอบรหัสอย่างละเอียดเพื่อทำความเข้าใจว่าไฟล์ถูกล็อคอยู่ที่ไหน

ในกรณีของฉันฉันกำลังส่งไฟล์เป็นไฟล์แนบอีเมลก่อนที่จะดำเนินการย้าย

ดังนั้นไฟล์จึงถูกล็อคสองสามวินาทีจนกระทั่งไคลเอ็นต์ SMTP ส่งอีเมลเสร็จสิ้น

วิธีแก้ปัญหาที่ฉันนำมาใช้คือการย้ายไฟล์ก่อนแล้วจึงส่งอีเมล สิ่งนี้ช่วยแก้ไขปัญหาให้ฉันได้

วิธีแก้ปัญหาอื่นที่เป็นไปได้ซึ่งฮัดสันได้กล่าวไว้ก่อนหน้านี้คือการกำจัดวัตถุหลังการใช้งาน

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

หากไฟล์ถูกใช้งานFile.Move()จะไม่ทำงาน & ให้ข้อผิดพลาดเดียวกัน หากเพียงแค่เพิ่มไฟล์ลงในอีเมลฉันไม่คิดว่ามันจะผิดพลาดเมื่อใช้งานในระหว่างการAttachments.Add()ดำเนินการเพราะนี่เป็นเพียงการคัดลอก หากทำด้วยเหตุผลบางประการคุณสามารถคัดลอกไปยังไดเรกทอรีชั่วคราวให้แนบสำเนา & ลบไฟล์ที่คัดลอกหลังจากนั้น แต่ฉันไม่คิดว่าถ้า OP ต้องการแก้ไขไฟล์และใช้สิ่งนั้นโซลูชันประเภทนี้ (ซึ่งคุณไม่ได้แสดงรหัสของเฉพาะส่วนที่แนบมา) จะทำงานได้ .Dispose()เป็นความคิดที่ดีเสมอ แต่ไม่เกี่ยวข้องที่นี่เว้นแต่จะเปิดไฟล์ใน op ก่อนหน้า
vapcguy

1

ฉันมีสถานการณ์ต่อไปนี้ที่ทำให้เกิดข้อผิดพลาดเดียวกัน:

  • อัปโหลดไฟล์ไปยังเซิร์ฟเวอร์
  • จากนั้นกำจัดไฟล์เก่าหลังจากอัปโหลดแล้ว

ไฟล์ส่วนใหญ่มีขนาดเล็ก แต่มีขนาดเล็กและพยายามลบไฟล์เหล่านั้นส่งผลให้เกิดข้อผิดพลาดในการเข้าถึงไฟล์ไม่ได้

มันไม่ง่ายเลยที่จะหาวิธีแก้ปัญหานั้นง่ายพอ ๆ กับการรอ "เพื่อให้งานเสร็จสมบูรณ์":

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

-1

รหัสด้านล่างของฉันแก้ปัญหานี้ แต่ฉันขอแนะนำก่อนอื่นคุณต้องเข้าใจสิ่งที่ทำให้เกิดปัญหานี้และลองวิธีแก้ปัญหาที่คุณสามารถหาได้โดยการเปลี่ยนรหัส

ฉันสามารถให้วิธีอื่นในการแก้ปัญหานี้ แต่ทางออกที่ดีกว่าคือการตรวจสอบโครงสร้างการเข้ารหัสของคุณและพยายามวิเคราะห์สิ่งที่ทำให้เกิดขึ้นหากคุณไม่พบวิธีแก้ปัญหาใด ๆ คุณสามารถไปกับรหัสด้านล่างนี้

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
ปัญหาเล็กน้อยเกี่ยวกับรหัสนี้: 1) หากคุณต้องการโทรGC.*()แล้วคุณอาจมีปัญหาอื่น ๆ เกี่ยวกับรหัสของคุณ 2) ข้อความเป็นภาษาท้องถิ่นและเปราะบางใช้ HRESULT แทน 3) คุณอาจต้องการที่จะนอนหลับด้วยTask.Delay()(และสิบวินาทีก็มากเกินไปในหลายกรณี) 4) คุณไม่ได้มีเงื่อนไขการออก: รหัสนี้อาจแขวน forver 5) คุณไม่ต้องการgotoที่นี่แน่นอน 6) การจับExceptionมักเป็นความคิดที่ไม่ดีในกรณีนี้ก็เพราะ ... 6) หากมีสิ่งอื่นเกิดขึ้นคุณก็จะกลืนความผิดพลาดไป
Adriano Repetti

@AdrianoRepetti ความคิดเห็นแรกของฉันบอกว่าอย่าใช้รหัสนี้ลองหาวิธีแก้ไขอื่น ๆ นี่จะเป็นตัวเลือกสุดท้ายและถ้าข้อผิดพลาดนี้เกิดขึ้นรหัสหยุดลง แต่ถ้าคุณจัดการกับระบบข้อผิดพลาดนี้จะรอให้ไฟล์ว่างหลังจากนั้นมันจะเริ่ม การทำงานและฉันไม่ประสบปัญหาอื่น ๆ กับ GC. * ในขณะที่ใช้รหัสนี้ฉันมีระบบการทำงานที่ใช้รหัสนี้อยู่แล้วดังนั้นฉันจึงโพสต์อาจมีประโยชน์สำหรับใครบางคน
แอช

ฉันจะบอกว่าอย่าใช้รหัสนี้เลย (เพราะคะแนนที่ฉันได้กล่าวไว้ข้างต้น) และฉันจะไม่พิจารณาการทำงานนี้ในระบบที่แยง แต่นั่นเป็นเพียง POV ของฉัน รู้สึกไม่เห็นด้วย!
Adriano Repetti

1) ฉันใช้บริการ windows ซึ่งฉันใช้มันและฉันใช้ GC * จนถึงนี้ฉันไม่ประสบปัญหาใด ๆ กับสิ่งนี้ 2) ใช่ HRESULT สามารถเป็นตัวเลือกที่ดีกว่าในแง่ของการเข้ารหัสมาตรฐาน 3) ขึ้นอยู่กับสถานการณ์ที่คุณสามารถให้เวลาฉันเพิ่งแก้ไข มันถึง 5 วินาที 4) มันจะดีกว่าถ้าระบบรอให้ทรัพยากรฟรีแทนที่จะหยุดระบบด้วยข้อผิดพลาด 5) ใช่ฉันเห็นด้วยกับคุณยกเว้นการจัดการไม่ใช่ความคิดที่ดีเสมอไป แต่ถ้าข้อมูลโค้ดของคุณมีขนาดเล็กและคุณรู้ ที่นี่ฉันสามารถจัดการข้อยกเว้นแล้วการแก้ปัญหานี้เป็นตัวเลือกสำหรับคุณ
แอช

ดูเพิ่มเติม: docs.microsoft.com/en-us/archive/blogs/ricom/... กรณีที่ฉันต้องใช้เท่านั้น (และฉันเครียดเท่านั้น) GC.Collect()เมื่อต้องจัดการกับวัตถุ COM บางอย่าง
Adriano Repetti
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.