2009-06-13 3 views
84

Próbuję usunąć plik, po napisaniu czegoś w nim, z FileOutputStream. Jest to kod używam do pisania:file.delete() zwraca false, mimo że file.exists(), file.canRead(), file.canWrite(), file.canExecute() wszystko zwraca true

private void writeContent(File file, String fileContent) { 
    FileOutputStream to; 
    try { 
     to = new FileOutputStream(file); 
     to.write(fileContent.getBytes()); 
     to.flush(); 
     to.close(); 
    } catch (FileNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

Jak widać, ja przepłukać i zamknąć strumienia, ale gdy próbuję usunąć file.delete() zwraca false.

Sprawdziłem przed usunięciem, aby sprawdzić, czy plik istnieje, i: file.exists(), file.canRead(), file.canWrite(), file.canExecute() wszystkie zwracają wartość true. Zaraz po wywołaniu tych metod próbuję file.delete() i zwracam wartość false.

Czy jest coś, co zrobiłem źle?

+0

Zapomniałam wspomnieć, że żaden wyjątek zostanie złapany. –

+0

Czy jesteś pewien, że plik nie jest używany przez inny proces? Zablokowałeś to? Czy działa z funkcją deleteOnExit + exiting? –

+0

Z jakiego systemu operacyjnego korzystasz? Czy możesz ręcznie usunąć plik? Coś może mieć otwarty uchwyt do pliku. – akarnokd

Odpowiedz

44

To była dość dziwna sztuczka, która zadziałała. Chodzi o to, kiedy wcześniej przeczytałem treść pliku, użyłem BufferedReader. Po przeczytaniu zamknąłem bufor.

Tymczasem zmieniłem i teraz czytam treść przy użyciu FileInputStream. Po zakończeniu czytania zamykam strumień. A teraz działa.

Problem polega na tym, że nie mam tego wyjaśnienia.

Nie wiem, czy BufferedReader i FileOutputStream są niekompatybilne.

+4

Chciałbym się spierać jest to błąd: http://java.sun.com/javase/6/docs/api/java/io/BufferedReader.html#close() Mówi tam, że metoda powinna zamknąć strumień i wszelkie zasoby z nim związane. Zazwyczaj chciałbym zamknąć wszystkie strumienie w odwróconej sekwencji (ostatnie, które mają być otwarte są pierwszymi, które mają zostać zamknięte) za pomocą IOUtils.closeQuietly, ale zwykle jest to przesada. –

+2

Miałem ten dokładny problem. Myślałem, że zwariowałem. Dzięki za rozwiązanie! –

+13

To 2011 z JDK 7 i problem nadal nie jest naprawiony. Tak się cieszę, że znalazłem ten wątek - po prostu nie mogłem się zorientować, co było nie tak ... – David

2

Nie ma powodu, dla którego nie można usunąć tego pliku. Chciałbym sprawdzić, kto ma wstrzymać tego pliku. W systemie Unix/Linux możesz użyć narzędzia lsof, aby sprawdzić, który proces ma blokadę pliku. W oknach można użyć eksploratora procesów.

dla lsof, jest to tak proste jak powiedzenie:

lsof /path/and/name/of/the/file 

dla Process Explorer można użyć menu Znajdź i wpisz nazwę pliku, aby pokazać wam uchwyt, który skieruje Cię do procesu blokowania pliku.

tu jest jakiś kod, który robi to, co myślę, że trzeba zrobić:

FileOutputStream to; 

try { 
    String file = "/tmp/will_delete.txt"; 
    to = new FileOutputStream(file); 
    to.write(new String("blah blah").getBytes()); 
    to.flush(); 
    to.close(); 
    File f = new File(file); 
    System.out.print(f.delete()); 
} catch (FileNotFoundException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

Współpracuje na OS X. Nie testowałem go na oknach, ale podejrzewam, że to powinno działać na Windows zbyt. Przyznam również, że widziałem nieoczekiwane zachowanie w systemie Windows w.r.t. Obsługa plików.

+1

W przypadku systemu Windows można pobrać bezpłatny proces Explorer z MS: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx – akarnokd

3

Jak skomentował Jon Skeet, powinieneś zamknąć plik w ostatnim bloku {...}, aby upewnić się, że jest zawsze zamknięty. Zamiast połknąć wyjątki za pomocą e.printStackTrace, po prostu nie przechwytuj i nie dodawaj wyjątku do sygnatury metody. Jeśli nie można z jakiegokolwiek powodu, przynajmniej to zrobić:

catch(IOException ex) { 
    throw new RuntimeException("Error processing file XYZ", ex); 
} 

Teraz pytanie numer # 2:

Co jeśli to zrobić:

... 
to.close(); 
System.out.println("Please delete the file and press <enter> afterwards!"); 
System.in.read(); 
... 

Byłbyś w stanie usunąć plik?

Ponadto pliki są opróżniane, gdy są zamknięte. Używam IOUtils.closeQuietly (...), więc używam metody flush, aby upewnić się, że zawartość pliku istnieje, zanim spróbuję ją zamknąć (IOUtils.closeQuietly nie generuje wyjątków). Coś takiego:

... 
try { 
    ... 
    to.flush(); 
} catch(IOException ex) { 
    throw new CannotProcessFileException("whatever", ex); 
} finally { 
    IOUtils.closeQuietly(to); 
} 

Tak więc wiem, że zawartość pliku jest tam. Ponieważ zazwyczaj liczy się dla mnie, że treść pliku jest zapisana, a nie, czy plik może być zamknięty, czy nie, to naprawdę nie ma znaczenia, czy plik został zamknięty, czy nie. W twoim przypadku, jeśli jest to ważne, poleciłbym zamknięcie pliku samemu i potraktowanie wyjątków według.

+0

Próbowałem najpierw: zamykanie strumienia wyjściowego w bloku finally. I to nie zadziałało. Co się stało, gdy próbowałem przeczytać po tym, to, że dostałem wiadomość, że strumień został zamknięty. Po przełączeniu i odczytaniu pliku za pomocą FileInputReader, nie wystąpiła żadna z "złych" rzeczy opisanych powyżej. –

1

Mam nadzieję, że to pomoże. Natknąłem się na podobny problem, gdy nie mogłem usunąć mojego pliku po tym, jak mój kod java zrobił kopię zawartości do drugiego folderu. Po rozszerzeniu google, jawnie zadeklarowałem każdą zmienną związaną z operacją na plikach i wywołałem metodę close() każdego obiektu operacji na plikach i ustawiono na NULL. Następnie jest funkcja o nazwie System.gc(), która wyczyści mapowanie plików i/o (nie jestem pewien, po prostu powiem, co jest podane na stronach internetowych).

Oto mój przykładowy kod:

public void start() { 
    File f = new File(this.archivePath + "\\" + this.currentFile.getName()); 
    this.Copy(this.currentFile, f); 

    if(!this.currentFile.canWrite()){ 
     System.out.println("Write protected file " + 
      this.currentFile.getAbsolutePath()); 

     return; 
    } 


    boolean ok = this.currentFile.delete(); 
    if(ok == false){ 
     System.out.println("Failed to remove " + this.currentFile.getAbsolutePath()); 
     return; 
    } 
} 

private void Copy(File source, File dest) throws IOException { 
    FileInputStream fin; 
    FileOutputStream fout; 
    FileChannel cin = null, cout = null; 
    try { 
     fin = new FileInputStream(source); 
     cin = fin.getChannel(); 
     fout = new FileOutputStream(dest); 
     cout = fout.getChannel(); 

     long size = cin.size(); 
     MappedByteBuffer buf = cin.map(FileChannel.MapMode.READ_ONLY, 0, size); 

     cout.write(buf); 
     buf.clear(); 
     buf = null; 

     cin.close(); 
     cin = null; 

     fin.close(); 
     fin = null; 

     cout.close(); 
     cout = null; 

     fout.close(); 
     fout = null; 

     System.gc(); 

    } catch (Exception e){ 
     this.message = e.getMessage(); 
     e.printStackTrace(); 
    } 
} 
90

Kolejny błąd w Javie. Rzadko je znajduję, tylko mój drugi w mojej 10 letniej karierze. To jest moje rozwiązanie, o czym wspominali inni. Mam Nether używane System.gc(). Ale tutaj, w moim przypadku, jest to absolutnie kluczowe. Dziwne? TAK!

finally 
{ 
    try 
    { 
     in.close(); 
     in = null; 
     out.flush(); 
     out.close(); 
     out = null; 
     System.gc(); 
    } 
    catch (IOException e) 
    { 
     logger.error(e.getMessage()); 
     e.printStackTrace(); 
    } 
} 
+7

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 – andreadi

+6

Mimo że nie otworzyłem go żadnym strumieniem (po prostu wykonując "nowy plik (ścieżkę)"), napotkałem ten sam problem i dodanie 'System.gc()' zanim 'delete()' sprawdziło się! – ixM

+1

Jaki jest drugi błąd? –

0

Wystąpił problem raz w Ruby gdzie potrzebne pliki w oknach „fsync”, aby rzeczywiście móc zawrócić i ponownie odczytać plik po zapisaniu go i zamykając go. Być może jest to podobna manifestacja (a jeśli tak, to myślę, że to błąd Windowsa).

15

Próbowałem tej prostej rzeczy i wydaje się, że działa.

file.setWritable(true); 
file.delete(); 

To działa dla mnie.

Jeśli to nie zadziała, spróbuj uruchomić aplikację Java z sudo, jeśli na systemie Linux i jako administrator, gdy jesteś w systemie Windows. Aby upewnić się, że Java ma uprawnienia do zmiany właściwości pliku.

+1

Dla tego problemu; zazwyczaj ludzie mówią o ustawianiu referencji jako zerowej lub wywołują system.gc(); ale dla mnie nawet po restarcie serwera pliki nie zostały usunięte !!Ale file.setWritable (true); po prostu pracował .. – Deepak

0

Żadne z wymienionych tutaj rozwiązań nie zadziałało w mojej sytuacji. Moim rozwiązaniem było użycie pętli while, próba usunięcia pliku, z 5-sekundowym (konfigurowalnym) limitem bezpieczeństwa.

File f = new File("/path/to/file"); 

int limit = 20; //Only try for 5 seconds, for safety 
while(!f.delete() && limit > 0){ 
    synchronized(this){ 
     try { 
      this.wait(250); //Wait for 250 milliseconds 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    limit--; 
} 

Stosując powyższą pętlę pracował bez konieczności wykonywania jakichkolwiek ręczne zbieranie śmieci lub ustawienie strumienia null itp

+0

Co S.O. używasz? Jeśli możesz mieć dostęp do STREAMS, zamknij je, to zadziała. Ale jeśli plik jest "już" zablokowany, oznacza to, że masz problem. – marcolopes

+1

-1 Zapętlenie w kodzie do usunięcia pliku nie jest świetnym pomysłem. Dlaczego po prostu nie skorzystać z opcji gc(), która działa? – bharal

+0

@bharal Notice Stwierdzam powyżej, że żadne z innych rozwiązań (w tym gc()) nie działało w moim konkretnym przypadku. Chociaż zgadzam się na użycie pętli while while is ideal, może to być odpowiednie rozwiązanie w pewnych okolicznościach. Dodanie dodatkowej kontroli do powyższego kodu, na przykład limitu czasu lub maksymalnej zmiennej iteracji, byłoby dobrym sposobem na zwiększenie bezpieczeństwa pętli while. – etech

2

Jeśli pracujesz w Eclipse IDE, to może oznaczać, że nie masz w pobliżu plik z poprzedniej wersji aplikacji. Kiedy miałem ten sam komunikat o błędzie przy próbie usunięcia pliku, to był powód. Wygląda na to, że Eclipse IDE nie zamyka wszystkich plików po zakończeniu aplikacji.

0

Problem może być taki, że plik jest nadal widziany jako otwarty i zablokowany przez program; lub może jest to składnik z twojego programu, w którym został otwarty, więc musisz upewnić się, że używasz metody dispose(), aby rozwiązać ten problem. tj.JFrame frame; .... frame.dispose();

0

Trzeba zamknąć wszystkich strumieni lub użyć try-with-Blok zasobów

static public String head(File file) throws FileNotFoundException, UnsupportedEncodingException, IOException 
{ 
    final String readLine; 
    try (FileInputStream fis = new FileInputStream(file); 
      InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); 
      LineNumberReader lnr = new LineNumberReader(isr)) 
    { 
     readLine = lnr.readLine(); 
    } 
    return readLine; 
} 
1

odpowiedź brzmi kiedy załadować plik, trzeba zastosować „Zamknij” sposób, w każdym wierszu kod, działa mi

0

jeśli file.delete() wysyła false, w większości przypadków uchwyt Bufferedreader nie zostanie zamknięty. Po prostu blisko i wydaje mi się, że działa normalnie.

5

Przed próbą usunięcia/zmiany nazwy dowolnego pliku należy upewnić się, że wszystkie czytniki lub programy piszące (np. BufferedReader/InputStreamReader/BufferedWriter) są poprawnie zamknięte.

Podczas próby odczytu/zapisu danych z/do pliku, plik jest zatrzymywany przez proces i nie jest zwalniany do momentu zakończenia wykonywania programu. Jeśli chcesz wykonać operacje usuwania/zmiany nazwy przed zakończeniem programu, musisz użyć metody close(), która jest dostarczana z klasami java.io.*.

+0

Dotyczy to tylko systemu Windows. Na prawdziwym O/S możesz usuwać i zmieniać nazwy otwartych plików. – Archie

0

Miałem ten sam problem w systemie Windows. Czytałem plik w linii scala po linii z

Source.fromFile(path).getLines() 

Teraz czytam je jako całość z

import org.apache.commons.io.FileUtils._ 

// encoding is null for platform default 
val content=readFileToString(new File(path),null.asInstanceOf[String]) 

która zamyka plik poprawnie po przeczytaniu i teraz

new File(path).delete 

Prace.

0

dla Eclipse/NetBeans

Ponownie uruchom IDE i uruchom ponownie swój kod to tylko sztuczka praca dla mnie po jednej godzinie długiej walce.

Oto mój kod:

File file = new File("file-path"); 
if(file.exists()){ 
    if(file.delete()){ 
    System.out.println("Delete"); 
    } 
    else{ 

     System.out.println("not delete"); 
    } 
} 

wyjściowa:

Usuń