2011-08-09 12 views
9

Myślałem, że to jest całkowicie trywialne zadanie, ale sprawiło mi to trochę bólu głowy. Chciałbym otworzyć plik, aby zapewnić sobie wyłączny dostęp, przetestować pod pewnymi warunkami, a następnie go usunąć.Jak poprawnie otworzyć plik do usunięcia?

Teraz używam podejście 99%:

FileStream s = null; 
try { 
    s = new FileStream (
     path, 
     FileMode.Open, 
     FileAccess.ReadWrite, 
     FileShare.None); 
    // some stuff about the file is checked here 
    s.Dispose(); 
    // hope the file is not accessed by someone else... 
    File.Delete (path); 
    return true; 
} 
catch (IOException) { 
    if (s !=null) s.Dispose(); 
    return false; 
} 

To zazwyczaj działa, ale pomyślałem, że będzie lepszy sposób, który pozwala uniknąć stanu krawędzi.

Otwarcie pliku z flagą DeleteOnClose nie działa, ponieważ wspomniana kontrola (która występuje po otwarciu z już ustawioną flagą usunięcia) może oznaczać, że plik nie powinien zostać usunięty.

+0

Nie jesteś pewien, czy to pomoże, ale czy spojrzałeś na projekt [transakcyjnego menedżera plików] (http://transactionalfilemgr.codeplex.com/) na codeplex? – Oded

+3

Czy próbowałeś otworzyć plik z FileShare.Delete i wywołać File.Delete przed pozbyciem się strumienia? – Fox32

+0

Na czym właściwie polega problem? Pierwszy otwarty może wywołać wyjątek IOException, jeśli plik jest już zablokowany (lub został usunięty przez kogoś innego) w taki sam sposób, jak plik File.Delete. Łapiesz i radzisz sobie z wyjątkiem, więc gdzie to stwarza problem? – Eddy

Odpowiedz

7

coś takiego:

using (FileStream file = new FileStream(path, 
     FileMode.Open, 
     FileAccess.ReadWrite, 
     FileShare.Delete)) 
    { 
     // you can read the file here and check your stuff 
     File.Delete(path); 
    } 

PS: zwróć uwagę na '' przy użyciu słowa kluczowego. To pozwala mieć czystszy kod, ponieważ zajmuje się usuwanie połączeń.

+0

Co do komentarzy, czy nie pozwoliłoby to różnym aplikacjom na dostęp do pliku? – mafu

+1

@mafutrct - FileShare.Delete oznacza "umożliwia późniejsze usunięcie pliku". Inna aplikacja może go usunąć, ale nie pisz do niego ani nie czytaj z niego. –

+0

Chociaż w moim przypadku usunięcie pliku nie byłoby problemem. Raczej zapisanie pliku będzie - zamierzam nadać inny Q za to. – mafu

1

Po pierwsze, naśladujesz wyrażenie "używanie" i robisz to w niewłaściwy sposób. Powinieneś wyrzucić strumień plików tylko raz, w klauzuli finally, nie dwa razy w próbie i catch. Ale lepiej użyj.

using (FileStream s = new FileStream()) 
{ 
} 

Po drugie, jesteś najlepszym rozwiązaniem jest transakcyjny NTFS (jeden z opakowania można znaleźć w Nabu Biblioteki: https://dev.triflesoft.org/mercurial/nabu/), jednak transakcyjny NTFS jest ograniczone do NTFS i Windows Vista +, więc jeśli trzeba FAT16/FAT32 lub Windows XP, to nie jest droga.


Możesz również spróbować przenieść/zmienić nazwę otwieranego pliku, aby uniemożliwić dostęp innym procesom, ale jest to również ograniczone do NTFS również AFAIR.


Jeśli nie potrzebujesz natychmiastowego usunięcia pliku, możesz skorzystać z funkcji SetupQue SetupDueble.

+0

Utylizacja w ramach próby jest wymagane, ponieważ nie mogę usunąć otwartego pliku. – mafu

+0

@mafutrct użyj close zamiast dispose then. –

+0

@ScottChamberlain: Nie rozumiem, jak to pomaga. Nie zamykaj i usuń mapę do tego samego kodu dla FileStream? – mafu

0

Nie można całkowicie zapobiec możliwości wystąpienia wyścigu. Biorąc pod uwagę, że program jest w tarapatach, jeśli między kontroli i usunąć plik zostanie zmodyfikowany istnieją co najmniej 2 obejścia widzę:

  • Uzyskaj nazwę pliku temp, zmień nazwę pliku do pliku tymczasowego, należy sprawdzić i zmień nazwę w razie potrzeby (może to prowadzić do nowych problemów w zależności od logiki biznesowej).
  • Możesz ustawić atrybut readonly na pliku przed jego sprawdzeniem.