简体   繁体   English

file.delete()返回false,即使file.exists(),file.canRead(),file.canWrite(),file.canExecute()都返回true

[英]file.delete() returns false even though file.exists(), file.canRead(), file.canWrite(), file.canExecute() all return true

I'm trying to delete a file, after writing something in it, with FileOutputStream . 我正在尝试使用FileOutputStream删除文件后写入文件。 This is the code I use for writing: 这是我用来编写的代码:

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

As it is seen, I flush and close the stream, but when I try to delete, file.delete() returns false. 如图所示,我刷新并关闭流,但是当我尝试删除时, file.delete()返回false。

I checked before deletion to see if the file exists, and: file.exists() , file.canRead() , file.canWrite() , file.canExecute() all return true. 我在删除前检查了文件是否存在,并且: file.exists()file.canRead()file.canWrite()file.canExecute()都返回true。 Just after calling these methods I try file.delete() and returns false. 在调用这些方法之后,我尝试使用file.delete()并返回false。

Is there anything I've done wrong? 有什么我做错了吗?

Another bug in Java. Java中的另一个错误。 I seldom find them, only my second in my 10 year career. 我很少找到他们,只是我10年职业生涯中的第二个。 This is my solution, as others have mentioned. 正如其他人所提到的,这是我的解决方案。 I have nether used System.gc() . 我有nether使用System.gc() But here, in my case, it is absolutely crucial. 但就我而言,这绝对是至关重要的。 Weird? 奇怪的? YES! 是!

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

It was pretty odd the trick that worked. 这个诀窍很奇怪。 The thing is when I have previously read the content of the file, I used BufferedReader . 事情是,当我以前读过文件的内容时,我使用了BufferedReader After reading, I closed the buffer. 读完后,我关闭了缓冲区。

Meanwhile I switched and now I'm reading the content using FileInputStream . 同时我切换了,现在我正在使用FileInputStream读取内容。 Also after finishing reading I close the stream. 完成阅读后,我关闭了流。 And now it's working. 现在它正在发挥作用。

The problem is I don't have the explanation for this. 问题是我对此没有解释。

I don't know BufferedReader and FileOutputStream to be incompatible. 我不知道BufferedReaderFileOutputStream是不兼容的。

I tried this simple thing and it seems to be working. 我尝试过这个简单的事情似乎很有效。

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

It works for me. 这个对我有用。

If this does not work try to run your Java application with sudo if on linux and as administrator when on windows. 如果这不起作用,请尝试使用sudo运行Java应用程序(如果在Linux上)和管理员运行Windows时。 Just to make sure Java has rights to change the file properties. 只是为了确保Java有权更改文件属性。

Before trying to delete/rename any file, you must ensure that all the readers or writers (for ex: BufferedReader / InputStreamReader / BufferedWriter ) are properly closed. 在尝试删除/重命名任何文件之前,必须确保正确关闭所有读取器或编写器(例如: BufferedReader / InputStreamReader / BufferedWriter )。

When you try to read/write your data from/to a file, the file is held by the process and not released until the program execution completes. 当您尝试从/向文件读取/写入数据时,该文件由进程保留,并且在程序执行完成之前不会释放。 If you want to perform the delete/rename operations before the program ends, then you must use the close() method that comes with the java.io.* classes. 如果要在程序结束之前执行删除/重命名操作,则必须使用java.io.*类附带的close()方法。

As Jon Skeet commented, you should close your file in the finally {...} block, to ensure that it's always closed. 正如Jon Skeet评论的那样,您应该在finally {...}块中关闭文件,以确保它始终关闭。 And, instead of swallowing the exceptions with the e.printStackTrace, simply don't catch and add the exception to the method signature. 并且,不要使用e.printStackTrace吞下异常,而只是不捕获并将异常添加到方法签名中。 If you can't for any reason, at least do this: 如果你出于任何原因不能,至少这样做:

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

Now, question number #2: 现在,问题编号#2:

What if you do this: 如果你这样做怎么办:

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

Would you be able to delete the file? 你能删除这个文件吗?

Also, files are flushed when they're closed. 此外,文件在关闭时会刷新。 I use IOUtils.closeQuietly(...), so I use the flush method to ensure that the contents of the file are there before I try to close it (IOUtils.closeQuietly doesn't throw exceptions). 我使用IOUtils.closeQuietly(...),所以我使用flush方法确保在我尝试关闭它之前文件的内容在那里(IOUtils.closeQuietly不会抛出异常)。 Something like this: 像这样的东西:

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

So I know that the contents of the file are in there. 所以我知道文件的内容在那里。 As it usually matters to me that the contents of the file are written and not if the file could be closed or not, it really doesn't matter if the file was closed or not. 因为通常对我来说文件的内容是写的而不是文件是否可以关闭,所以文件是否关闭并不重要。 In your case, as it matters, I would recommend closing the file yourself and treating any exceptions according. 在您的情况下,重要的是,我建议您自己关闭文件并根据情况处理任何异常。

If you are working in Eclipse IDE, that could mean that you haven't close the file in the previous launch of the application. 如果您在Eclipse IDE中工作,则可能意味着您尚未在先前启动的应用程序中关闭该文件。 When I had the same error message at trying to delete a file, that was the reason. 当我在尝试删除文件时遇到相同的错误消息时,原因就在于此。 It seems, Eclipse IDE doesn't close all files after termination of an application. 看来,Eclipse IDE在应用程序终止后不会关闭所有文件。

There is no reason you should not be able to delete this file. 您没有理由不能删除此文件。 I would look to see who has a hold on this file. 我会看看谁对这个文件有所保留。 In unix/linux, you can use the lsof utility to check which process has a lock on the file. 在unix / linux中,您可以使用lsof实用程序来检查哪个进程对文件具有锁定。 In windows, you can use process explorer. 在Windows中,您可以使用进程资源管理器。

for lsof, it's as simple as saying: 对于lsof来说,就像说:

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

for process explorer you can use the find menu and enter the file name to show you the handle which will point you to the process locking the file. 对于进程资源管理器,您可以使用查找菜单并输入文件名来显示句柄,该句柄将指向锁定文件的进程。

here is some code that does what I think you need to do: 这里有一些代码可以完成我认为你需要做的事情:

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

It works fine on OS X. I haven't tested it on windows but I suspect it should work on Windows too. 它在OS X上工作正常。我没有在Windows上测试它,但我怀疑它也适用于Windows。 I will also admit seeing some unexpected behavior on Windows wrt file handling. 我还承认在Windows wrt文件处理上看到了一些意外的行为。

Hopefully this will help. 希望这会有所帮助。 I came across similar problem where i couldn't delete my file after my java code made a copy of the content to the other folder. 我遇到了类似的问题,在我的java代码将内容的副本复制到另一个文件夹后,我无法删除我的文件。 After extensive googling, i explicitly declared every single file operation related variables and called the close() method of each file operation object, and set them to NULL. 在广泛的谷歌搜索之后,我显式地声明了每个文件操作相关的变量,并调用每个文件操作对象的close()方法,并将它们设置为NULL。 Then, there is a function called System.gc(), which will clear up the file i/o mapping (i'm not sure, i just tell what is given on the web sites). 然后,有一个名为System.gc()的函数,它将清除文件i / o映射(我不确定,我只是告诉网站上给出的内容)。

Here is my example code: 这是我的示例代码:

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

答案是当你加载文件时,你需要应用“关闭”方法,在任何代码行中,对我有用

None of the solutions listed here worked in my situation. 这里列出的解决方案都不适用于我的情况。 My solution was to use a while loop, attempting to delete the file, with a 5 second (configurable) limit for safety. 我的解决方案是使用while循环,尝试删除文件,安全性限制为5秒(可配置)。

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

Using the above loop worked without having to do any manual garbage collecting or setting the stream to null, etc. 使用上面的循环工作,无需进行任何手动垃圾收集或将流设置为null等。

The problem could be that the file is still seen as opened and locked by a program; 问题可能是文件仍被视为打开并被程序锁定; or maybe it is a component from your program that it had been opened in, so you have to ensure you use the dispose() method to solve that problem. 或者它可能是程序中已打开的组件,因此您必须确保使用dispose()方法来解决该问题。 ie JFrame frame; .... frame.dispose(); JFrame frame; .... frame.dispose(); JFrame frame; .... frame.dispose();

You have to close all of the streams or use try-with-resource block 您必须关闭所有流或使用try-with-resource块

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

if file.delete() is sending false then in most of the cases your Bufferedreader handle will not be closed. 如果file.delete()发送false,那么在大多数情况下,您的Bufferedreader句柄将不会被关闭。 Just close and it seems to work for me normally. 刚关闭,它似乎通常对我有用。

I had the same problem on Windows. 我在Windows上遇到了同样的问题。 I used to read the file in scala line by line with 我曾经逐行读取scala中的文件

Source.fromFile(path).getLines()

Now I read it as a whole with 现在我把它作为一个整体阅读

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

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

which closes the file properly after reading and now 在阅读后现在正确关闭文件

new File(path).delete

works. 作品。

FOR Eclipse/NetBeans 对于Eclipse / NetBeans

Restart your IDE and run your code again this is only trick work for me after one hour long struggle. 重新启动你的IDE并再次运行你的代码这只是经过一个小时的努力后才对我有用。

Here is my code: 这是我的代码:

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

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

Output: 输出:

Delete 删除

There was a problem once in ruby where files in windows needed an "fsync" to actually be able to turn around and re-read the file after writing it and closing it. 在ruby中有一个问题,Windows中的文件需要一个“fsync”来实际上能够转换并在写入并关闭它之后重新读取该文件。 Maybe this is a similar manifestation (and if so, I think a windows bug, really). 也许这是一个类似的表现(如果是这样,我认为一个Windows bug,真的)。

Another corner case that this could happen: if you read/write a JAR file through a URL and later try to delete the same file within the same JVM session. 另一种可能发生的极端情况:如果您通过URL读取/写入JAR文件,稍后尝试在同一JVM会话中删除相同的文件。

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!

Reason is that the internal JAR file handling logic of Java, tends to cache JarFile entries: 原因是Java的内部JAR文件处理逻辑,倾向于缓存JarFile条目:

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

And each JarFile (rather, the underlying ZipFile structure) would hold a handle to the file, right from the time of construction up until close() is invoked: 每个JarFile (相反,底层的ZipFile结构)都会保存文件的句柄,从构造开始直到调用close()

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;

There's a good explanation on this NetBeans issue . 这个NetBeans问题有一个很好的解释。


Apparently there are two ways to "fix" this: 显然有两种方法来“修复”这个:

  • You can disable the JAR file caching - for the current URLConnection , or for all future URLConnection s (globally) in the current JVM session: 您可以禁用JAR文件缓存 - 对于当前的URLConnection ,或者当前JVM会话中的所有未来URLConnection (全局):

     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!] You can manually purge the JarFile from the cache when you are done with it. [HACK WARNING!]完成后,您可以从缓存中手动清除JarFile The cache manager sun.net.www.protocol.jar.JarFileFactory is package-private, but some reflection magic can get the job done for you: 缓存管理器sun.net.www.protocol.jar.JarFileFactory是包私有的,但是一些反射魔法可以为你完成工作:

     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. 

Please note: All this is based on Java 8 codebase ( 1.8.0_144 ); 请注意:所有这些都基于Java 8代码库( 1.8.0_144 ); they may not work with other / later versions. 它们可能无法与其他/更高版本一起使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM