我正在尝试使用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。
我做错了什么?
答案 0 :(得分:94)
Java中的另一个错误。我很少找到他们,只是我10年职业生涯中的第二个。正如其他人所提到的,这是我的解决方案。我使用了System.gc()
。但就我而言,这绝对是至关重要的。奇怪的? YES!
finally
{
try
{
in.close();
in = null;
out.flush();
out.close();
out = null;
System.gc();
}
catch (IOException e)
{
logger.error(e.getMessage());
e.printStackTrace();
}
}
答案 1 :(得分:45)
这个技巧很奇怪。事情是,当我以前读过文件的内容时,我使用了BufferedReader
。读完后,我关闭了缓冲区。
同时我切换了,现在我正在使用FileInputStream
阅读内容。完成阅读后,我关闭了流。现在它正在发挥作用。
问题是我对此没有解释。
我不知道BufferedReader
和FileOutputStream
是不兼容的。
答案 2 :(得分:17)
我尝试了这个简单的事情,它似乎正在发挥作用。
file.setWritable(true);
file.delete();
它对我有用。
如果这不起作用,请尝试使用sudo运行Java应用程序(如果在Linux上)和管理员运行Windows时。只是为了确保Java有权更改文件属性。
答案 3 :(得分:5)
在尝试删除/重命名任何文件之前,您必须确保所有读者或作者(例如BufferedReader
/ InputStreamReader
/ BufferedWriter
)都已正确关闭。
当您尝试从/向文件读取/写入数据时,该文件由进程保留,并且在程序执行完成之前不会释放。如果要在程序结束前执行删除/重命名操作,则必须使用close()
类附带的java.io.*
方法。
答案 4 :(得分: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);
}
所以我知道文件的内容在那里。因为通常对我来说文件的内容是写的而不是文件是否可以关闭,所以文件是否关闭并不重要。在您的情况下,重要的是,我建议您自己关闭文件并根据情况处理任何异常。
答案 5 :(得分:2)
如果您在Eclipse IDE中工作,这可能意味着您在上一次启动应用程序时没有关闭该文件。当我在尝试删除文件时遇到相同的错误消息时,原因就在于此。看来,Eclipse IDE在终止应用程序后不会关闭所有文件。
答案 6 :(得分: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 w.r.t上看到了一些意想不到的行为。文件处理。
答案 7 :(得分:1)
答案是当你加载文件时,你需要应用“关闭”方法,在任何代码行中,对我有用
答案 8 :(得分: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();
}
}
答案 9 :(得分: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--;
}
使用上面的循环工作,无需进行任何手动垃圾收集或将流设置为null等等。
答案 10 :(得分:0)
在ruby中曾经出现过一个问题,Windows中的文件需要一个“fsync”来实际转换并在写入并关闭文件后重新读取该文件。也许这是一个类似的表现形式(如果是这样,我认为是一个Windows bug,真的)。
答案 11 :(得分:0)
问题可能是文件仍被视为打开并被程序锁定;或者它可能是您的程序中已打开的组件,因此您必须确保使用dispose()
方法来解决该问题。
即JFrame frame;
....
frame.dispose();
答案 12 :(得分: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;
}
答案 13 :(得分:0)
如果file.delete()发送为false,那么在大多数情况下,您的Bufferedreader句柄将不会被关闭。刚关闭,它似乎通常对我有用。
答案 14 :(得分: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
作品。
答案 15 :(得分:0)
FOR Eclipse / NetBeans
重新启动你的IDE并再次运行你的代码这只是经过一个小时的挣扎后才对我有用。
这是我的代码:
{{1}}
<强>输出:强>
删除
答案 16 :(得分:0)
可能还会发生的另一种极端情况:如果您通过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!
原因是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;
this NetBeans issue上有很好的解释。
显然,有两种方法可以“解决”此问题:
您可以为当前URLConnection
或当前JVM会话中所有未来的URLConnection
(全局)禁用JAR文件缓存:
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
);它们可能不适用于其他/更高版本。