file.delete() возвращает false, хотя file.exists(), file.canRead(), file.canWrite(), file.canExecute() все возвращают true
Я пытаюсь удалить файл, после записи чего-либо в нем, с 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()
возвращает ложь
Я проверил перед удалением, чтобы увидеть, существует ли файл, и: file.exists()
, file.canRead()
, file.canWrite()
, file.canExecute()
все возвращают истину. Просто после вызова этих методов я пытаюсь file.delete()
и возвращает ложь.
Что-то я сделал не так?
17 ответов
Это был довольно странный трюк, который сработал. Дело в том, что когда я предварительно прочитал содержимое файла, я использовал BufferedReader
, После прочтения я закрыл буфер.
Тем временем я переключился, и теперь я читаю контент, используя FileInputStream
, Также после окончания чтения я закрываю поток. И теперь это работает.
Проблема в том, что у меня нет объяснения этому.
Я не знаю BufferedReader
а также FileOutputStream
быть несовместимым
Еще одна ошибка в Java. Я редко нахожу их, только мой второй в моей 10-летней карьере. Это мое решение, как уже упоминали другие. Я нигде не пользовался System.gc()
, Но здесь, в моем случае, это абсолютно важно. Weird? ДА!
finally
{
try
{
in.close();
in = null;
out.flush();
out.close();
out = null;
System.gc();
}
catch (IOException e)
{
logger.error(e.getMessage());
e.printStackTrace();
}
}
Я попробовал эту простую вещь, и она, кажется, работает.
file.setWritable(true);
file.delete();
Меня устраивает.
Если это не работает, попробуйте запустить приложение Java с помощью sudo, если в Linux, и в качестве администратора, когда в Windows. Просто чтобы убедиться, что у Java есть права на изменение свойств файла.
Прежде чем пытаться удалить / переименовать любой файл, вы должны убедиться, что все читатели или писатели (например,: BufferedReader
/InputStreamReader
/BufferedWriter
) правильно закрыты.
Когда вы пытаетесь прочитать / записать ваши данные из / в файл, файл удерживается процессом и не освобождается до завершения выполнения программы. Если вы хотите выполнить операции удаления / переименования до завершения программы, вы должны использовать close()
метод, который идет с java.io.*
классы.
Как прокомментировал Джон Скит, вы должны закрыть свой файл в блоке 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);
}
Так что я знаю, что содержимое файла там. Поскольку для меня обычно имеет значение, что содержимое файла записано, а не то, может ли файл быть закрыт или нет, действительно не имеет значения, был ли файл закрыт или нет. В вашем случае, если это имеет значение, я бы порекомендовал закрыть файл самостоятельно и обработать все исключения в соответствии.
Если вы работаете в Eclipse IDE, это может означать, что вы не закрыли файл при предыдущем запуске приложения. Когда у меня появилось такое же сообщение об ошибке при попытке удалить файл, это было причиной. Кажется, Eclipse IDE не закрывает все файлы после завершения приложения.
Нет причин, по которым вы не сможете удалить этот файл. Я хотел бы посмотреть, кто держит этот файл. В unix/linux вы можете использовать утилиту lsof, чтобы проверить, какой процесс заблокировал файл. В Windows вы можете использовать Process Explorer.
для 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 произошла непредвиденная ситуация.
Ответ: когда вы загружаете файл, вам нужно применить метод close в любой строке кода, который мне подходит
Надеюсь, это поможет. Я столкнулся с подобной проблемой, когда я не мог удалить свой файл после того, как мой Java-код скопировал содержимое в другую папку. После интенсивного поиска в Google я явно объявил переменные, связанные с каждой отдельной файловой операцией, и вызвал метод close() для каждого объекта файловой операции и установил для них значение NULL. Затем есть функция System.gc(), которая очистит файл ввода / вывода (я не уверен, я просто расскажу, что дается на веб-сайтах).
Вот мой пример кода:
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();
}
}
Проблема может заключаться в том, что файл по-прежнему считается открытым и заблокированным программой; или, может быть, это компонент из вашей программы, в котором он был открыт, поэтому вы должны убедиться, что вы используете dispose()
метод для решения этой проблемы. т.е. JFrame frame;
....
frame.dispose();
У меня была такая же проблема на 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
работает.
Если file.delete() отправляет false, то в большинстве случаев ваш дескриптор Bufferedreader не будет закрыт. Просто близко, и это, кажется, работает для меня нормально.
Однажды возникла проблема в ruby, когда файлам в Windows требовался "fsync", чтобы действительно иметь возможность развернуться и перечитать файл после его записи и закрытия. Может быть, это аналогичное проявление (и если да, то я думаю, что ошибка Windows, на самом деле).
ДЛЯ 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");
}
}
Выход:
удалять
Другой случай, когда это может произойти: если вы читаете / пишете файл 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!
Причина в том, что внутренняя логика обработки файлов JAR Java имеет тенденцию кешировать 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-файла - для текущего
URLConnection
или на все будущееURLConnection
s (глобально) в текущем сеансе JVM: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
); они могут не работать с другими / более поздними версиями.
Ни одно из перечисленных здесь решений не сработало в моей ситуации. Мое решение состояло в том, чтобы использовать цикл 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--;
}
Использование вышеуказанного цикла работало без необходимости какого-либо ручного сбора мусора или установки потока на нуль и т. Д.
Вы должны закрыть все потоки или использовать блок 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;
}