file.delete (), file.exists (), file.canRead (), file.canWrite (), file.canExecute (), tümü true döndürse de false döndürür


90

İle bir şey yazdıktan sonra bir dosyayı silmeye çalışıyorum FileOutputStream. Yazmak için kullandığım kod bu:

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

Görüldüğü gibi akışı temizleyip kapatıyorum, ancak silmeye çalıştığımda file.delete()false döndürüyor.

Ben dosya var olmadığını görmek için silme önce kontrol ve: file.exists(), file.canRead(), file.canWrite(), file.canExecute()bütün dönüş doğrudur. Bu yöntemleri çağırdıktan hemen sonra deniyorum file.delete()ve yanlış döndürüyorum.

Yanlış yaptığım bir şey var mı?


Hiçbir istisnanın yakalanmadığını söylemeyi unuttum.
Jenny Smith

Dosyanın başka bir işlem tarafından kullanılmadığından emin misiniz? Kilitledin mi DeleteOnExit + çıkışıyla çalışıyor mu?
benim

Hangi işletim sistemi üzerinde çalışıyorsunuz? Dosyayı manuel olarak silebilir misiniz? Bir şey dosyaya açık bir tanıtıcı tutabilir.
akarnokd

Başka bir işlem tarafından kullanılıp kullanılmadığını nasıl öğrenebilirim? Ben kilitlemedim. DeleteOnExit yöntemini kullanamıyorum, çünkü dosyayı silmem ve bundan sonra başvuruma devam etmem gerekiyor. Fikir, bir oturum için farklı bir klasördeki dosyaları depolamak için kullanılan geçici bir klasörü boşaltmaya çalışmam. Başvurumdaki aç düğmesine bastığımda, başka dosyalara yer açmak için klasörün boşaltılması gerektiği anlamına geliyor. O dosyaya yazarken bölümü atlarsam sorun olmaz ve onu silebilirim.
Jenny Smith

1
Lütfen floşunuzu ve kapanışınızı bir blok halinde sarabilir misiniz? Bunu yaptığını ve işe yaramadığını biliyorum, ancak soruna netlik katacak.
bharal

Yanıtlar:


101

Java'daki başka bir hata. Onları nadiren buluyorum, sadece 10 yıllık kariyerimde ikinci. Başkalarının da bahsettiği gibi bu benim çözümüm. Nether kullandım System.gc(). Ama benim durumumda bu kesinlikle çok önemli. Tuhaf? EVET!

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

8
Herhangi bir akışla açmasam da (sadece a yapıyor new File(path)), aynı sorunla karşılaştım ve çalışmasını sağlamadan System.gc()önce delete()ekledim!
ixM

1
Diğer hata nedir?
bogdan.mustiata

benim için wotk değil. Silemediğim dosya, indirilenFromURL dosyasının bir ZIP dosyası. Güzel olan şey, indirilen dosyanın silinecek olmasıdır. Herhangi bir fikir?
Andrea_86

Benim için çalıştı. Ve @andreadi FileChannel.map'i kodumda hiç kullanmadım. Görünüşe göre bu hata çözülemez olarak kapatıldı, bu da beni inanılmaz kılıyor çünkü System.gchile her seferinde çalışıyor.
Adam Burley

Tek gc () yardımcı olmayabilirSystem.gc(); result = file.delete(); if (!result){ Thread.sleep(100); System.gc(); result = file.delete(); }
notes-jj

48

İşe yarayan numara oldukça tuhaftı. Sorun şu ki, daha önce dosyanın içeriğini okudum, kullandım BufferedReader. Okuduktan sonra tamponu kapattım.

Bu arada değiştirdim ve şimdi kullanarak içeriği okuyorum FileInputStream. Ayrıca okumayı bitirdikten sonra dereyi kapatıyorum. Ve şimdi çalışıyor.

Sorun şu ki, bunun için bir açıklamam yok.

Bilmiyorum BufferedReaderve FileOutputStreamuyumsuz olmak.


4
O zaman bunun bir hata olduğunu iddia ediyorum: java.sun.com/javase/6/docs/api/java/io/… Orada yöntemin akışı ve onunla ilişkili tüm kaynakları kapatması gerektiğini söylüyor. IOUtils.closeQuietly kullanarak genellikle ters sıradaki tüm akışları kapatmayı seviyorum (en son açılanlar kapatılacak olanlardır), ancak aşırı olma eğilimindedir.
Ravi Wallau

2
Tam da bu sorunu yaşıyordum ve delirdiğimi düşündüm. Çözüm için teşekkürler!
Electrons_Ahoy

14
JDK 7 ile 2011 yılı ve sorun hala çözülmedi. Bu konuyu bulduğuma çok sevindim - neyin yanlış olduğunu anlayamadım ...
David

Okuyup kapattığım ve sonra silmeye çalıştığım bir dosyayla ilgili çok can sıkıcı bir sorun yaşadım. Burada bahsedilen hiçbir şey yardımcı olmadı. Sonra bir saat sonra, dosya başka bir kullanıcı tarafından oluşturulduğundan, bunun sadece dosya hakları olduğunu keşfettim :-D
runholen

Sadece karanlıkta bir bıçak ... finalize()Temizliği sağlamak için arayabilir misin ? Veya belki set to = null? Bkz . Sonlandırmayı ve Çöp Toplamayı Zorlama .
jww

19

Bu basit şeyi denedim ve çalışıyor gibi görünüyor.

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

Benim için çalışıyor.

Bu işe yaramazsa, Java uygulamanızı linux'taysa sudo ile ve Windows'ta yönetici olarak çalıştırmayı deneyin. Sadece Java'nın dosya özelliklerini değiştirme haklarına sahip olduğundan emin olmak için.


1
Bu problem için; genellikle insanlar referansları boş olarak ayarlamaktan veya system.gc () 'yi çağırmaktan bahsederler; ama benim için sunucu yeniden başlatıldıktan sonra bile dosyalar silinmiyordu !! Ancak file.setWritable (true); Sadece çalıştı ..
Deepak Singhal

6

Herhangi bir dosyayı silmeye / yeniden adlandırmaya çalışmadan önce, tüm okuyucuların veya yazarların (örneğin: BufferedReader/ InputStreamReader/ BufferedWriter) düzgün şekilde kapatıldığından emin olmalısınız .

Verilerinizi bir dosyadan / dosyadan okumaya / yazmaya çalıştığınızda, dosya işlem tarafından tutulur ve programın yürütülmesi tamamlanana kadar serbest bırakılmaz. Program bitmeden silme / yeniden adlandırma işlemlerini gerçekleştirmek istiyorsanız close(), java.io.*sınıflarla birlikte gelen yöntemi kullanmalısınız .


1
Bu yalnızca Windows için geçerlidir. Herhangi bir gerçek işletim sisteminde açık dosyaları silebilir ve yeniden adlandırabilirsiniz.
Archie

3

Jon Skeet'in dediği gibi, her zaman kapalı olduğundan emin olmak için dosyanızı nihayet {...} bloğunda kapatmalısınız. Ve istisnaları e.printStackTrace ile yutmak yerine, istisnayı yakalamayın ve yöntem imzasına eklemeyin. Herhangi bir nedenle yapamıyorsanız, en azından şunu yapın:

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

Şimdi, soru numarası 2:

Ya bunu yaparsan:

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

Dosyayı silebilir misiniz?

Ayrıca, dosyalar kapatıldıklarında temizlenir. IOUtils.closeQuietly (...) kullanıyorum, bu yüzden dosyayı kapatmaya çalışmadan önce dosyanın içeriğinin orada olmasını sağlamak için flush yöntemini kullanıyorum (IOUtils.closeQuietly istisnalar atmıyor). Bunun gibi bir şey:

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

Yani dosyanın içeriğinin orada olduğunu biliyorum. Benim için genellikle önemli olduğu için dosyanın içeriğinin yazılı olması ve dosyanın kapatılıp kapatılamaması önemli değil, dosyanın kapatılıp kapatılmaması gerçekten önemli değil. Sizin durumunuzda, önemli olduğu için, dosyayı kendiniz kapatmanızı ve istisnaları uygun şekilde ele almanızı tavsiye ederim.


İlk şeyi denedim - nihayet blokta çıktı akışını kapatmak. Ve işe yaramadı. Ondan sonra okumaya çalışırsam olan şey, akışın kapatıldığını söyleyen bir mesaj almamdı. Dosyayı FileInputReader ile değiştirirken ve okurken, yukarıda açıklanan "kötü" şeylerin hiçbiri olmadı.
Jenny Smith

2

Bu dosyayı silememeniz için hiçbir sebep yok. Bu dosyada kimin elinde olduğunu görmek isterim. Unix / linux'ta, dosya üzerinde hangi işlemin kilitli olduğunu kontrol etmek için lsof yardımcı programını kullanabilirsiniz. Windows'ta işlem gezginini kullanabilirsiniz.

lsof için şunu söylemek kadar basit:

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

işlem gezgini için bul menüsünü kullanabilir ve sizi dosyayı kilitleme sürecini gösterecek olan tutamacı göstermek için dosya adını girebilirsiniz.

İşte yapmanız gerektiğini düşündüğüm şeyi yapan bir kod:

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

OS X'te gayet iyi çalışıyor. Windows üzerinde test etmedim ancak Windows'ta da çalışması gerektiğinden şüpheleniyorum. Windows wrt dosya işlemede bazı beklenmedik davranışlar gördüğümü de itiraf edeceğim.


1
Pencereler için, MS ücretsiz Süreci Explorer indirebilirsiniz: technet.microsoft.com/en-us/sysinternals/bb896653.aspx
akarnokd

2

Eclipse IDE'de çalışıyorsanız, bu, uygulamanın önceki açılışında dosyayı kapatmadığınız anlamına gelebilir. Bir dosyayı silmeye çalışırken aynı hata mesajını aldığımda, bunun nedeni buydu. Görünüşe göre Eclipse IDE, bir uygulamanın sonlandırılmasından sonra tüm dosyaları kapatmıyor.


1

Umarım bu yardımcı olur. Java kodum içeriğin bir kopyasını diğer klasöre yaptıktan sonra dosyamı silemediğimde benzer bir sorunla karşılaştım. Kapsamlı bir googling işleminden sonra, her bir dosya işlemiyle ilgili değişkenleri açıkça bildirdim ve her dosya işlemi nesnesinin close () yöntemini çağırdım ve bunları NULL olarak ayarladım. Ardından, dosya i / o eşlemesini temizleyecek olan System.gc () adlı bir işlev vardır (emin değilim, sadece web sitelerinde ne verildiğini söylüyorum).

İşte örnek kodum:

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

1

cevap, dosyayı yüklediğinizde, herhangi bir kod satırında "kapat" yöntemini uygulamanız gerekir, bana çalışır


0

Ruby'de bir kez, Windows'taki dosyaların, dosyayı yazıp kapattıktan sonra gerçekten dönüp yeniden okuyabilmek için bir "fsync" gerektirdiği bir sorun vardı. Belki bu benzer bir tezahürdür (ve eğer öyleyse, gerçekten bir pencere hatası olduğunu düşünüyorum).


0

Burada listelenen çözümlerden hiçbiri benim durumumda işe yaramadı. Çözümüm, güvenlik için 5 saniyelik (yapılandırılabilir) bir sınırla dosyayı silmeye çalışan bir while döngüsü kullanmaktı.

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

Yukarıdaki döngüyü kullanmak, herhangi bir manuel çöp toplama veya akışı null olarak ayarlama vb. Yapmak zorunda kalmadan çalıştı.


Ne SO kullanıyorsun? AKIŞLARA erişiminiz varsa, kapatın, çalışacaktır. Ancak dosya "zaten" kilitliyse, bir sorununuz var demektir.
marcolopes

1
Bir dosyayı silmek için kodunuzda -1 döngü yapmak harika bir fikir değildir. Neden sadece çalışan gc () seçeneğini kullanmıyorsunuz?
bharal

@bharal Bildirimi Yukarıda diğer çözümlerden hiçbirinin (gc () dahil) benim özel durumumda işe yaramadığını belirtmiştim. Bir while döngüsü kullanmanın ideal olmadığını kabul etsem de, belirli durumlarda uygun bir çözüm olabilir. Yukarıdaki koda bir zaman aşımı veya maksimum yineleme değişkeni gibi ek bir kontrol eklemek, while döngüsünü daha güvenli hale getirmek için iyi bir yol olabilir.
etech

@etech, eğer dosyanız hiç var olmadıysa, sonsuz bir döngü oluşturdunuz.
bharal

0

Sorun, dosyanın hala bir program tarafından açılmış ve kilitlenmiş olarak görülmesi olabilir; veya belki de programınızın içinde açılmış olduğu bir bileşendir, bu nedenle dispose()bu sorunu çözmek için yöntemi kullandığınızdan emin olmalısınız . yaniJFrame frame; .... frame.dispose();


0

Tüm akışları kapatmanız veya kaynakla deneme bloğunu kullanmanız gerekir

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

0

file.delete () yanlış gönderiyorsa, çoğu durumda Bufferedreader tanıtıcınız kapatılmayacaktır. Sadece kapat ve benim için normal çalışıyor gibi görünüyor.


0

Windows'ta da aynı sorunu yaşadım. Dosyayı satır satır okurdum.

Source.fromFile(path).getLines()

Şimdi bir bütün olarak okuyorum

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

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

hangi dosyayı okuduktan sonra düzgün bir şekilde kapatır ve şimdi

new File(path).delete

İşler.


0

Eclipse / NetBeans İÇİN

IDE'nizi yeniden başlatın ve kodunuzu tekrar çalıştırın, bu benim için bir saatlik uzun bir mücadeleden sonra sadece hile işidir.

İşte kodum:

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

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

Çıktı:

Sil


0

Bunun olabileceği başka bir köşe durumu: bir JAR dosyasını bir JAR dosyasını okur / yazarsanız URLve daha sonra aynı dosyayı aynı JVM oturumu içinde silmeye çalışırsanız.

File f = new File("/tmp/foo.jar");
URL j = f.toURI().toURL();

URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
URLConnection c = u.openConnection();

// open a Jar entry in auto-closing manner
try (InputStream i = c.getInputStream()) {

    // just read some stuff; for demonstration purposes only
    byte[] first16 = new byte[16];
    i.read(first16);
    System.out.println(new String(first16));
}

// ...

// i is now closed, so we should be good to delete the jar; but...
System.out.println(f.delete());     // says false!

Bunun nedeni, Java'nın dahili JAR dosyası işleme mantığının JarFilegirişleri önbelleğe alma eğiliminde olmasıdır :

// inner class of `JarURLConnection` that wraps the actual stream returned by `getInputStream()`

class JarURLInputStream extends FilterInputStream {
    JarURLInputStream(InputStream var2) {
        super(var2);
    }

    public void close() throws IOException {
        try {
            super.close();
        } finally {

            // if `getUseCaches()` is set, `jarFile` won't get closed!

            if (!JarURLConnection.this.getUseCaches()) {
                JarURLConnection.this.jarFile.close();
            }
        }
    }
}

Ve her biri JarFile(daha ziyade, temel ZipFileyapı), yapım close()anından çağrılana kadar dosyanın bir tanıtıcısını tutacaktır :

public ZipFile(File file, int mode, Charset charset) throws IOException {
    // ...

    jzfile = open(name, mode, file.lastModified(), usemmap);

    // ...
}

// ...

private static native long open(String name, int mode, long lastModified,
                                boolean usemmap) throws IOException;

Bu NetBeans sorunu hakkında iyi bir açıklama var .


Görünüşe göre bunu "düzeltmenin" iki yolu var:

  • JAR dosyası önbelleğe almayı devre dışı bırakabilirsiniz - mevcut JVM oturumundaki mevcut URLConnectionveya gelecekteki tüm e-postalar için URLConnection(global olarak):

    URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
    URLConnection c = u.openConnection();
    
    // for only c
    c.setUseCaches(false);
    
    // globally; for some reason this method is not static,
    // so we still need to access it through a URLConnection instance :(
    c.setDefaultUseCaches(false);
    
  • [HACK WARNING!] İşinizJarFile bittiğinde önbellekten manuel olarak temizleyebilirsiniz . Önbellek yöneticisi sun.net.www.protocol.jar.JarFileFactorypakete özeldir, ancak biraz yansıma sihri işi sizin için halledebilir:

    class JarBridge {
    
        static void closeJar(URL url) throws Exception {
    
            // JarFileFactory jarFactory = JarFileFactory.getInstance();
            Class<?> jarFactoryClazz = Class.forName("sun.net.www.protocol.jar.JarFileFactory");
            Method getInstance = jarFactoryClazz.getMethod("getInstance");
            getInstance.setAccessible(true);
            Object jarFactory = getInstance.invoke(jarFactoryClazz);
    
            // JarFile jarFile = jarFactory.get(url);
            Method get = jarFactoryClazz.getMethod("get", URL.class);
            get.setAccessible(true);
            Object jarFile = get.invoke(jarFactory, url);
    
            // jarFactory.close(jarFile);
            Method close = jarFactoryClazz.getMethod("close", JarFile.class);
            close.setAccessible(true);
            //noinspection JavaReflectionInvocation
            close.invoke(jarFactory, jarFile);
    
            // jarFile.close();
            ((JarFile) jarFile).close();
        }
    }
    
    // and in your code:
    
    // i is now closed, so we should be good to delete the jar
    JarBridge.closeJar(j);
    System.out.println(f.delete());     // says true, phew.
    

Lütfen dikkat: Tüm bunlar Java 8 kod tabanına ( 1.8.0_144) dayanmaktadır ; diğer / sonraki sürümlerle çalışmayabilirler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.