Saya memiliki beberapa kode dan ketika dijalankan, ia melempar IOException
, mengatakan itu
Proses tidak dapat mengakses file 'nama file' karena sedang digunakan oleh proses lain
Apa artinya ini, dan apa yang bisa saya lakukan?
c#
.net
language-agnostic
ioexception
Adriano Repetti
sumber
sumber
Jawaban:
Apa penyebabnya?
Pesan kesalahannya cukup jelas: Anda mencoba mengakses file, dan itu tidak dapat diakses karena proses lain (atau bahkan proses yang sama) sedang melakukan sesuatu dengannya (dan tidak memungkinkan berbagi apa pun).
Debugging
Mungkin sangat mudah untuk dipecahkan (atau cukup sulit untuk dipahami), tergantung pada skenario spesifik Anda. Mari kita lihat.
Proses Anda adalah satu-satunya untuk mengakses file itu.
Anda yakin proses lainnya adalah proses Anda sendiri. Jika Anda tahu Anda membuka file itu di bagian lain dari program Anda, maka pertama-tama Anda harus memeriksa apakah Anda benar-benar menutup pegangan file setelah setiap kali digunakan. Berikut adalah contoh kode dengan bug ini:
Untungnya
FileStream
implementasinyaIDisposable
, jadi mudah untuk membungkus semua kode Anda di dalamusing
pernyataan:Pola ini juga akan memastikan bahwa file tidak akan dibiarkan terbuka jika ada pengecualian (mungkin itu alasan file digunakan: ada yang tidak beres, dan tidak ada yang menutupnya; lihat posting ini sebagai contoh).
Jika semuanya tampak baik-baik saja (Anda yakin Anda selalu menutup setiap file yang Anda buka, bahkan dalam kasus pengecualian) dan Anda memiliki beberapa utas yang berfungsi, maka Anda memiliki dua opsi: pengerjaan ulang kode Anda untuk membuat serial akses file (tidak selalu bisa dilakukan dan tidak selalu ingin) atau menerapkan pola coba lagi . Ini adalah pola yang cukup umum untuk operasi I / O: Anda mencoba melakukan sesuatu dan jika terjadi kesalahan Anda menunggu dan mencoba lagi (apakah Anda bertanya pada diri sendiri mengapa, misalnya, Windows Shell membutuhkan waktu untuk memberi tahu Anda bahwa file sedang digunakan dan tidak bisa dihapus?). Di C # ini cukup mudah untuk diterapkan (lihat juga contoh yang lebih baik tentang disk I / O , jaringan dan akses basis data ).
Harap perhatikan kesalahan umum yang sering kita lihat di StackOverflow:
Dalam hal ini
ReadAllText()
akan gagal karena file sedang digunakan (File.Open()
di baris sebelumnya). Untuk membuka file sebelumnya tidak hanya tidak perlu tetapi juga salah. Hal yang sama berlaku untuk semuaFile
fungsi yang tidak mengembalikan pegangan ke file Anda bekerja dengan:File.ReadAllText()
,File.WriteAllText()
,File.ReadAllLines()
,File.WriteAllLines()
dan lain-lain (sepertiFile.AppendAllXyz()
fungsi) semua akan membuka dan menutup file sendiri.Proses Anda bukan satu-satunya untuk mengakses file itu.
Jika proses Anda bukan satu-satunya untuk mengakses file itu, maka interaksi bisa lebih sulit. Sebuah pola coba lagi akan membantu (jika file tersebut tidak harus terbuka oleh orang lain tetapi, maka Anda memerlukan utilitas seperti Process Explorer untuk memeriksa siapa yang melakukan apa ).
Cara yang harus dihindari
Jika berlaku, selalu gunakan menggunakan pernyataan untuk membuka file. Seperti yang disebutkan pada paragraf sebelumnya, ini akan secara aktif membantu Anda menghindari banyak kesalahan umum (lihat posting ini untuk contoh tentang bagaimana tidak menggunakannya ).
Jika memungkinkan, cobalah untuk memutuskan siapa yang memiliki akses ke file tertentu dan memusatkan akses melalui beberapa metode terkenal. Jika, misalnya, Anda memiliki file data di mana program Anda membaca dan menulis, maka Anda harus memasukkan semua kode I / O di dalam satu kelas. Ini akan membuat debug lebih mudah (karena Anda selalu dapat meletakkan breakpoint di sana dan melihat siapa yang melakukan apa) dan juga itu akan menjadi titik sinkronisasi (jika diperlukan) untuk beberapa akses.
Jangan lupa operasi I / O selalu bisa gagal, contoh umum adalah ini:
Jika seseorang menghapus file setelah
File.Exists()
tetapi sebelumnyaFile.Delete()
, maka itu akan melemparIOException
di tempat di mana Anda salah merasa aman.Kapan pun memungkinkan, terapkan pola coba lagi , dan jika Anda menggunakan
FileSystemWatcher
, pertimbangkan untuk menunda tindakan (karena Anda akan diberi tahu, tetapi aplikasi mungkin masih bekerja secara eksklusif dengan file itu).Skenario lanjutan
Ini tidak selalu mudah, jadi Anda mungkin perlu berbagi akses dengan orang lain. Jika, misalnya, Anda membaca dari awal dan menulis hingga akhir, Anda memiliki setidaknya dua opsi.
1) berbagi hal yang sama
FileStream
dengan fungsi sinkronisasi yang tepat (karena tidak aman untuk thread ). Lihat ini dan posting ini sebagai contoh.2) menggunakan
FileShare
enumerasi untuk menginstruksikan OS untuk memungkinkan proses lain (atau bagian lain dari proses Anda sendiri) untuk mengakses file yang sama secara bersamaan.Dalam contoh ini saya menunjukkan cara membuka file untuk ditulis dan dibagikan untuk dibaca; harap dicatat bahwa ketika membaca dan menulis tumpang tindih, itu menghasilkan data yang tidak terdefinisi atau tidak valid. Ini adalah situasi yang harus ditangani ketika membaca. Perhatikan juga bahwa ini tidak membuat akses ke
stream
thread-safe, jadi objek ini tidak dapat dibagi dengan banyak utas kecuali jika akses entah bagaimana disinkronkan (lihat tautan sebelumnya). Opsi berbagi lainnya tersedia, dan mereka membuka skenario yang lebih kompleks. Silakan merujuk ke MSDN untuk detail lebih lanjut.Secara umum N proses dapat membaca dari file yang sama secara bersamaan, tetapi hanya satu yang harus menulis, dalam skenario terkontrol Anda bahkan dapat mengaktifkan tulisan bersamaan tetapi ini tidak dapat digeneralisasi dalam beberapa paragraf teks di dalam jawaban ini.
Apakah mungkin untuk membuka kunci file yang digunakan oleh proses lain? Itu tidak selalu aman dan tidak begitu mudah tetapi ya, itu mungkin .
sumber
File.Create(path)
, Anda harus menambahkan.Close()
di akhir itu sebelum Anda menulisnya. Ada jebakan seperti itu, selainusing
pernyataan untuk menulis file, kemudian menghapusnya. Anda harus memposting kode dalam pertanyaan Anda untuk bagaimana Anda membuat & menghapus file Anda. Tetapi mungkin sejalan dengan sesuatu yang disebutkan di atas.Directory.SetCreationTimeUTC()
tetapi gagal ketika File Explorer terbuka, mengklaim direktori sedang diakses oleh proses lain. Bagaimana saya harus menangani situasi ini?Menggunakan FileShare memperbaiki masalah saya membuka file bahkan jika dibuka oleh proses lain.
sumber
Mengalami masalah saat mengunggah gambar dan tidak dapat menghapusnya dan menemukan solusinya. gl hf
sumber
Saya mendapat kesalahan ini karena saya sedang melakukan File.Move ke path file tanpa nama file, perlu menentukan path lengkap di tujuan.
sumber
Kesalahan menunjukkan proses lain sedang mencoba mengakses file. Mungkin Anda atau orang lain membukanya saat Anda mencoba menulisnya. "Baca" atau "Salin" biasanya tidak menyebabkan ini, tetapi menulis ke sana atau memanggil delete akan membuatnya.
Ada beberapa hal mendasar untuk menghindari ini, seperti jawaban lain telah disebutkan:
Dalam
FileStream
operasi, letakkan diusing
blok denganFileShare.ReadWrite
mode akses.Sebagai contoh:
Catatan yang
FileAccess.ReadWrite
tidak mungkin jika Anda gunakanFileMode.Append
.Saya mengalami masalah ini ketika saya menggunakan aliran input untuk melakukan
File.SaveAs
ketika file sedang digunakan. Dalam kasus saya yang saya temukan, saya sebenarnya tidak perlu menyimpannya kembali ke sistem file sama sekali, jadi saya akhirnya hanya menghapus itu, tapi saya mungkin bisa mencoba membuat FileStream dalam sebuahusing
pernyataan denganFileAccess.ReadWrite
, seperti kode atas.Menyimpan data Anda sebagai file yang berbeda dan kembali untuk menghapus yang lama ketika ternyata tidak lagi digunakan, kemudian mengganti nama yang berhasil disimpan dengan nama yang asli adalah pilihan. Bagaimana Anda menguji file yang sedang digunakan dicapai melalui
baris dalam kode saya di bawah ini, dan dapat dilakukan dalam layanan Windows, dalam satu lingkaran, jika Anda memiliki file tertentu yang ingin Anda tonton dan hapus secara teratur ketika Anda ingin menggantinya. Jika Anda tidak selalu memiliki file yang sama, file teks atau tabel database dapat diperbarui bahwa layanan selalu memeriksa nama file, dan kemudian melakukan itu memeriksa proses & selanjutnya melakukan proses membunuh dan menghapusnya, seperti yang saya jelaskan di opsi selanjutnya. Perhatikan bahwa Anda akan memerlukan nama pengguna dan kata sandi akun yang memiliki hak Admin di komputer yang diberikan, tentu saja, untuk melakukan penghapusan dan proses akhir.
Ketika Anda tidak tahu apakah suatu file akan digunakan ketika Anda mencoba untuk menyimpannya, Anda bisa menutup semua proses yang bisa menggunakannya, seperti Word, jika itu dokumen Word, di depan save.
Jika lokal, Anda dapat melakukan ini:
Jika jarak jauh, Anda dapat melakukan ini:
di mana
txtUserName
dalam bentukDOMAIN\user
.Katakanlah Anda tidak tahu nama proses yang mengunci file. Kemudian, Anda dapat melakukan ini:
Catatan yang
file
harus menjadi jalur UNC:\\computer\share\yourdoc.docx
agarProcess
dapat mengetahui komputer apa yang aktif danp.MachineName
valid.Di bawah ini adalah kelas yang digunakan fungsi-fungsi ini, yang membutuhkan penambahan referensi
System.Management
. Kode ini awalnya ditulis oleh Eric J .:sumber
Seperti yang ditunjukkan oleh jawaban lain di utas ini, untuk menyelesaikan kesalahan ini Anda perlu memeriksa kode dengan hati-hati, untuk memahami di mana file terkunci.
Dalam kasus saya, saya mengirim file sebagai lampiran email sebelum melakukan operasi pemindahan.
Jadi file terkunci selama beberapa detik sampai klien SMTP selesai mengirim email.
Solusi yang saya adopsi adalah memindahkan file terlebih dahulu, dan kemudian mengirim email. Ini memecahkan masalah bagi saya.
Solusi lain yang mungkin, seperti yang ditunjukkan sebelumnya oleh Hudson, adalah membuang benda setelah digunakan.
sumber
File.Move()
tidak akan berfungsi & memberikan kesalahan yang sama. Jika hanya menambahkan file ke email saya tidak berpikir itu kesalahan saat digunakan selamaAttachments.Add()
operasi karena ini hanya operasi salin. Jika itu dilakukan karena alasan tertentu Anda bisa menyalinnya ke direktori Temp, lampirkan salinannya, & hapus file yang disalin sesudahnya. Tapi saya tidak berpikir, jika OP ingin memodifikasi file & menggunakannya, solusi semacam ini (yang Anda tidak menunjukkan kode, hanya bagian yang dilampirkan) akan berfungsi..Dispose()
selalu merupakan ide yang baik, tetapi tidak relevan di sini kecuali file dibuka di op sebelumnya.Saya memiliki skenario berikut yang menyebabkan kesalahan yang sama:
Sebagian besar file berukuran kecil, namun ada pula yang berukuran besar, sehingga berusaha menghapusnya menyebabkan tidak dapat mengakses kesalahan file .
Itu tidak mudah ditemukan, namun, solusinya sesederhana Menunggu "untuk tugas untuk menyelesaikan eksekusi":
sumber
Kode saya di bawah ini menyelesaikan masalah ini, tetapi saya sarankan Pertama-tama Anda perlu memahami apa yang menyebabkan masalah ini dan mencoba solusi yang dapat Anda temukan dengan mengubah kode
Saya dapat memberikan cara lain untuk mengatasi masalah ini, tetapi solusi yang lebih baik adalah dengan memeriksa struktur pengkodean Anda dan mencoba menganalisis apa yang menyebabkan hal ini terjadi, jika Anda tidak menemukan solusi apa pun, Anda dapat menggunakan kode ini di bawah ini.
sumber
GC.*()
maka Anda mungkin memiliki masalah lain dengan kode Anda. 2) Pesan dilokalkan dan rapuh , gunakan HRESULT sebagai gantinya. 3) Anda mungkin ingin tidur denganTask.Delay()
(dan sepuluh detik entah bagaimana berlebihan dalam banyak kasus). 4) Anda tidak memiliki kondisi keluar: kode ini bisa hang forver. 5) Anda pasti tidak perlu digoto
sini. 6) MenangkapException
biasanya merupakan ide yang buruk, dalam hal ini juga karena ... 6) Jika ada hal lain terjadi maka Anda menelan kesalahan.GC.Collect()
adalah ketika berurusan dengan beberapa objek COM.