Temel olarak, gerçekten açmaya çalışmadan önce dosyayı açma hakkım olup olmadığını kontrol etmek istiyorum; Mecbur kalmadıkça bu çek için bir dene / yakala kullanmak istemiyorum. Önceden kontrol edebileceğim bir dosya erişim özelliği var mı?
Temel olarak, gerçekten açmaya çalışmadan önce dosyayı açma hakkım olup olmadığını kontrol etmek istiyorum; Mecbur kalmadıkça bu çek için bir dene / yakala kullanmak istemiyorum. Önceden kontrol edebileceğim bir dosya erişim özelliği var mı?
Yanıtlar:
Bunu geçmişte sayısız kez yaptım ve neredeyse her yaptığımda, bu denemek bile hatalıydı.
Dosya izinleri (dosya varlığı bile) uçucudur - her an değişebilir. Murphy Yasası sayesinde bu, özellikle dosyayı kontrol etmeniz ve açmaya çalışmanız arasındaki kısa dönemi içerir. Önce kontrol etmeniz gerektiğini bildiğiniz bir bölgedeyseniz, değişiklik daha da olasıdır. Yine de garip bir şekilde, oldukça statik olma eğiliminde olan test veya geliştirme ortamlarınızda asla olmayacak. Bu, sorunun daha sonra izini sürmeyi zorlaştırır ve bu tür hataların üretime geçmesini kolaylaştırır.
Bunun anlamı, kontrolünüze rağmen dosya izinleri veya varlığı kötüyse, istisnayı hala idare edebilmeniz gerektiğidir. Dosyanın izinlerini önceden kontrol etseniz de etmeseniz de, istisna işleme kodu gereklidir . İstisna işleme kodu, varlığın veya izin kontrollerinin tüm işlevselliğini sağlar . Ek olarak, bunun gibi istisna işleyicilerin yavaş olduğu biliniyor olsa da, disk giriş / çıkışının daha da yavaş olduğunu ... çok daha yavaş olduğunu ve .Exists () işlevini çağırmak veya izinleri kontrol etmek ek bir geziye zorlayacaktır. dosya sistemi dışında.
Özetle, dosyayı açmaya çalışmadan önce yapılan ilk kontrol hem gereksiz hem de israftır. İstisna işlemeye göre ek bir faydası yoktur, performansınıza gerçekten zarar verir, yardımcı olmaz, korunması gereken daha fazla kod açısından maliyet ekler ve kodunuza ince hatalar ekleyebilir. İlk kontrolü yapmanın hiçbir avantajı yok. Bunun yerine, buradaki doğru şey, dosyayı açmaya çalışmak ve başarısız olursa iyi bir istisna işleyiciye çabalamaktır. Aynı şey, dosyanın var olup olmadığını kontrol etseniz bile geçerlidir. Bu muhakeme, herhangi bir geçici kaynak için geçerlidir .
Buraya benzer bir sorunla gelen herkes için hızlı ipucu:
DropBox gibi web senkronizasyon uygulamalarına dikkat edin. .NET'te "using" ifadesinin (Dispose pattern) bozuk olduğunu düşünerek 2 saat geçirdim.
Sonunda Dropbox'ın senkronize etmek için dosyaları arka planda sürekli olarak okuduğunu ve yazdığını fark ettim.
Bil bakalım Visual Studio Projeleri klasörüm nerede bulunuyor? Elbette "Dropbox'ım" klasörünün içinde.
Bu nedenle, uygulamamı Debug modunda çalıştırdığım için, okuduğu ve yazdığı dosyalara DropBox sunucusuyla senkronize edilmek üzere DropBox tarafından sürekli olarak erişiliyordu. Bu, kilitleme / erişim çatışmalarına neden oldu.
Bu yüzden en azından artık daha sağlam bir Dosya Açma fonksiyonuna ihtiyacım olduğunu biliyorum (yani, birden fazla deneme yapacak olan TryOpen ()). Çerçevenin zaten yerleşik bir parçası olmamasına şaşırdım.
[Güncelleme]
İşte benim yardımcı işlevim:
/// <summary>
/// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts.
/// </summary>
/// <param name="filePath">The full file path to be opened</param>
/// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param>
/// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param>
/// <param name="fileShare">Required file share enum value(see MSDN documentation)</param>
/// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param>
/// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param>
/// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns>
public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS)
{
FileStream fs = null;
int attempts = 0;
// Loop allow multiple attempts
while (true)
{
try
{
fs = File.Open(filePath, fileMode, fileAccess, fileShare);
//If we get here, the File.Open succeeded, so break out of the loop and return the FileStream
break;
}
catch (IOException ioEx)
{
// IOExcception is thrown if the file is in use by another process.
// Check the numbere of attempts to ensure no infinite loop
attempts++;
if (attempts > maximumAttempts)
{
// Too many attempts,cannot Open File, break and return null
fs = null;
break;
}
else
{
// Sleep before making another attempt
Thread.Sleep(attemptWaitMS);
}
}
}
// Reutn the filestream, may be valid or null
return fs;
}
using
arayan tarafından kullanılmalıdır ...
using
burada çalışmayacak. Kullanım bloğunun sonunda fs
zorla kapatılacaktır. Arayan kişiye KAPALI (çok işe yaramaz) bir filestream vereceksiniz!
İşte aradığınız çözüm
var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read,
System.Security.AccessControl.AccessControlActions.View,
MyPath);
if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read)
{
// Do your thing here...
}
bu, tüm dosyaların yolunun görünümüne dayalı olarak yeni bir okuma izni oluşturur ve ardından okunan dosya erişimine eşit olup olmadığını kontrol eder.
Önce Joel Coehoorn'un söylediği.
Ayrıca, mecbur kalmadıkça dene / yakala'yı kullanmaktan kaçınma arzunuzun altında yatan varsayımları da incelemelisiniz. İstisnalara bağlı olan mantıktan kaçınmanın tipik nedeni ( Exception
nesnelerin oluşturulması kötü performans gösterir) muhtemelen bir dosyayı açan kodla ilgili değildir.
Sanırım List<FileStream>
bir dizin alt ağacındaki her dosyayı açarak a'yı dolduran bir yöntem yazıyorsanız ve çok sayıda kişinin erişilemez olmasını bekliyorsanız, bir dosyayı açmaya çalışmadan önce dosya izinlerini kontrol etmek isteyebilirsiniz, böylece çok fazla istisna alın. Ama yine de istisnayı halledersiniz. Ayrıca, bunu yapan bir yöntem yazıyorsanız, muhtemelen programınızın tasarımında çok büyük bir yanlışlık vardır.
public static bool IsFileLocked(string filename)
{
bool Locked = false;
try
{
FileStream fs =
File.Open(filename, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None);
fs.Close();
}
catch (IOException ex)
{
Locked = true;
}
return Locked;
}
public static FileStream GetFileStream(String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, ref int attempts, int attemptWaitInMilliseconds)
{
try
{
return File.Open(filePath, fileMode, fileAccess, fileShare);
}
catch (UnauthorizedAccessException unauthorizedAccessException)
{
if (attempts <= 0)
{
throw unauthorizedAccessException;
}
else
{
Thread.Sleep(attemptWaitInMilliseconds);
attempts--;
return GetFileStream(filePath, fileMode, fileAccess, fileShare, ref attempts, attemptWaitInMilliseconds);
}
}
}
attempts
Ref tarafından neden geçilir? Bu hiç mantıklı değil. <=
Sadece yerine test etmek de yapmaz ==
.
throw ex
aslında yapılacak doğru şey olduğunu düşünüyorum.