91

我正在尝试删除一个文件,在其中写入一些内容后,使用FileOutputStream. 这是我用来编写的代码:

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

正如所见,我刷新并关闭了流,但是当我尝试删除时,file.delete()返回 false。

我在删除之前检查了文件是否存在,并且:file.exists()file.canRead()file.canWrite()file.canExecute()都返回true。就在调用这些方法之后,我尝试file.delete()返回 false。

有什么我做错了吗?

4

17 回答 17

104

Java 中的另一个错误。我很少找到它们,这只是我 10 年职业生涯中的第二个。正如其他人所提到的,这是我的解决方案。我已经用过System.gc()。但在这里,就我而言,这绝对是至关重要的。奇怪的?是的!

finally
{
    try
    {
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        System.gc();
    }
    catch (IOException e)
    {
        logger.error(e.getMessage());
        e.printStackTrace();
    }
}
于 2010-11-18T09:18:32.783 回答
49

奏效的把戏很奇怪。问题是当我之前阅读过文件的内容时,我使用了BufferedReader. 阅读后,我关闭了缓冲区。

同时我切换了,现在我正在使用FileInputStream. 同样在完成阅读后,我关闭了流。现在它正在工作。

问题是我没有对此的解释。

我不知道BufferedReaderFileOutputStream不相容。

于 2009-06-13T21:44:44.037 回答
19

我尝试了这个简单的事情,它似乎正在工作。

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

这个对我有用。

如果这不起作用,请尝试在 linux 上使用 sudo 运行您的 Java 应用程序,在 Windows 上使用管理员身份运行。只是为了确保 Java 有权更改文件属性。

于 2011-05-22T19:46:45.283 回答
6

在尝试删除/重命名任何文件之前,您必须确保所有读取器或写入器(例如:BufferedReader// InputStreamReaderBufferedWriter都已正确关闭。

当您尝试从/向文件读取/写入数据时,该文件由进程持有并且在程序执行完成之前不会被释放。如果要在程序结束前执行删除/重命名操作,则必须使用类close()自带的方法java.io.*

于 2014-02-27T09:30:40.683 回答
3

正如 Jon Skeet 评论的那样,您应该在 finally {...} 块中关闭您的文件,以确保它始终处于关闭状态。而且,不要使用 e.printStackTrace 吞下异常,而是不要捕获异常并将其添加到方法签名中。如果你不能出于任何原因,至少这样做:

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

现在,问题 #2:

如果你这样做怎么办:

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

你能删除文件吗?

此外,文件在关闭时会被刷新。我使用 IOUtils.closeQuietly(...),所以我使用 flush 方法来确保文件的内容在我尝试关闭它之前就在那里(IOUtils.closeQuietly 不会抛出异常)。像这样的东西:

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

所以我知道文件的内容在那里。因为对我来说通常重要的是文件的内容是否被写入,而不是文件是否可以关闭,所以文件是否关闭并不重要。就您而言,重要的是,我建议您自己关闭文件并根据情况处理任何异常。

于 2009-06-14T05:50:33.557 回答
2

您没有理由不能删除此文件。我想看看谁持有这个文件。在 unix/linux 中,您可以使用 lsof 实用程序来检查哪个进程对文件进行了锁定。在 Windows 中,您可以使用进程资源管理器。

对于 lsof,就这么简单:

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

对于进程资源管理器,您可以使用查找菜单并输入文件名以显示句柄,该句柄将指向锁定文件的进程。

这是一些我认为你需要做的代码:

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 上运行良好。我没有在 Windows 上测试过,但我怀疑它也应该在 Windows 上运行。我也承认在 Windows wrt 文件处理中看到了一些意想不到的行为。

于 2009-06-13T20:59:33.053 回答
2

如果您在 Eclipse IDE 中工作,这可能意味着您在之前启动应用程序时没有关闭该文件。当我在尝试删除文件时收到相同的错误消息时,这就是原因。似乎,Eclipse IDE 在应用程序终止后不会关闭所有文件。

于 2013-04-04T13:36:20.823 回答
1

希望这会有所帮助。我遇到了类似的问题,在我的 java 代码将内容复制到另一个文件夹后,我无法删除我的文件。经过广泛的谷歌搜索,我显式声明了每个文件操作相关的变量,并调用了每个文件操作对象的 close() 方法,并将它们设置为 NULL。然后,有一个名为 System.gc() 的函数,它将清除文件 i/o 映射(我不确定,我只是告诉网站上给出的内容)。

这是我的示例代码:

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();
    }
}
于 2009-11-10T08:24:08.827 回答
1

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

于 2014-01-16T04:00:03.243 回答
0

曾经在 ruby​​ 中存在一个问题,Windows 中的文件需要“fsync”才能在写入和关闭文件后真正转身并重新读取文件。也许这是一个类似的表现(如果是这样,我认为是一个 Windows 错误,真的)。

于 2011-03-01T15:09:29.167 回答
0

此处列出的解决方案均不适用于我的情况。我的解决方案是使用 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--;
}

使用上述循环无需进行任何手动垃圾收集或将流设置为空等。

于 2012-09-10T21:33:20.487 回答
0

问题可能是文件仍然被程序打开和锁定;或者它可能是您程序中的一个组件,它已在其中打开,因此您必须确保使用该dispose()方法来解决该问题。IEJFrame frame; .... frame.dispose();

于 2013-08-11T18:11:49.343 回答
0

您必须关闭所有流或使用 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;
}
于 2013-12-22T19:05:39.993 回答
0

如果 file.delete() 发送 false 那么在大多数情况下,您的 Bufferedreader 句柄将不会关闭。刚刚关闭,它似乎对我正常工作。

于 2014-02-03T08:48:26.790 回答
0

我在 Windows 上遇到了同样的问题。我曾经用 scala 逐行读取文件

Source.fromFile(path).getLines()

现在我把它作为一个整体来阅读

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

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

读取后正确关闭文件,现在

new File(path).delete

作品。

于 2015-12-15T18:07:36.757 回答
0

对于 Eclipse/NetBeans

重新启动您的 IDE 并再次运行您的代码,经过一小时的努力,这对我来说只是技巧工作。

这是我的代码:

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

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

输出:

删除

于 2017-03-29T18:33:06.150 回答
0

另一个可能发生这种情况的极端情况:如果您通过 a 读取/写入 JAR 文件URL,然后尝试在同一个 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!

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

并且每个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;

关于这个 NetBeans 问题有一个很好的解释。


显然有两种方法可以“解决”这个问题:

  • 您可以禁用 JAR 文件缓存 - 用于当前 JVM 会话中的 currentURLConnection或所有 future s(全局):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!]完成后,您可以手动JarFile从缓存中清除它。缓存管理器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.
    

请注意:所有这些都基于 Java 8 代码库 ( 1.8.0_144);它们可能不适用于其他/更高版本。

于 2019-02-20T02:15:01.680 回答