У меня есть код Java, который должен удалить мой существующий файл на моем устройстве, но он не работает, я не понимаю, почему. Он продолжает возвращать false, когда я пытаюсь использовать функцию .delete().
Вот мой код, я уже закрыл все буферы и записи, но он все еще не работает.
File saveFile = new File("save.txt");
File saveTemp = new File("temp.txt");
File playerFile = new File(player.username + ".txt");
String currentLine;
try {
FileWriter fw = new FileWriter(saveTemp, true);
BufferedWriter bw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bw);
FileReader fr = new FileReader("save.txt");
BufferedReader br = new BufferedReader(fr);
while((currentLine = br.readLine()) != null)
{
if (!currentLine.equals(player.username))
{
pw.println(currentLine);
}
}
pw.flush();
pw.close();
fr.close();
br.close();
bw.close();
fw.close();
saveFile.delete();
playerFile.delete();
File dump = new File("save.txt");
saveTemp.renameTo(dump);
} catch (Exception e) {
e.printStackTrace();
}
java.io.File
API устарел. Это означает, что он устарел (вы должны прекратить его использовать), но, учитывая, что это основной API, «устарел» как термин, специально используемый в ядре, означает «когда-нибудь в ближайшее время, это вообще не будет работать», и java.io.File
не является что - это будет работать через 10 лет. Но все равно не стоит его использовать. В его дизайне есть фундаментальные проблемы, которые означают, что это несовершенный API, и его нельзя (нельзя) исправить.
Один из его многочисленных недостатков заключается в том, что он не похож на Java в том, как он передает вам ошибки. Как ни странно, большая часть File
API сама по себе не выдает исключений, когда что-то идет не так. Вместо этого он возвращает шаткие вещи.
Например, file.list()
возвращает пустой массив, если вы запускаете его в пустом каталоге, но возвращает null
, если он не может выполнить задание (например, каталог не существует, или это файл, а не каталог, или, процесс java не имеет прав на чтение). Точно так же delete()
не вызывает исключения. Вместо того, чтобы указать на ошибку, он возвращает false
. Это не только не похоже на Java, это также означает, что невозможно узнать, почему delete()
не работает. Проблема с правами доступа? Файл не существует? Кто знает.
Простой вывод заключается в том, что вы всегда должны проверять возвращаемое значение всего, что вы делаете с объектом j.i.File
, но это сокращает путь. Истинное решение состоит в том, чтобы прекратить его использовать.
У нового API тоже есть проблемы, но гораздо меньше. Это также не устарело / не рекомендуется в смысле словаря английского языка: именно так современное Java-приложение должно взаимодействовать с файлами. Вы найдете его в упаковке java.nio.file
.
В отличие от j.i.File
API, этот генерирует исключения, когда что-то идет не так, и эти исключения сообщают вам, что они могут быть проверены как программой (иерархия типов, например, NoSuchFileException
, если вы хотите специально отреагировать на такую проблему), так и человеком. , в том, что сообщения об этих исключениях объясняют на английском языке, что не так.
Во-вторых, вы ДОЛЖНЫ безопасно закрывать объекты, представляющие системные ресурсы, а ваш код этого не делает. Есть удобный синтаксис try-with, который упрощает эту задачу, так что давайте сделаем и это!
В-третьих, вы сбрасываете, а затем закрываете. Это бессмысленно; close()
уже подразумевает сброс, нет причин вызывать flush() перед закрытием, он просто загромождает ваш код. На самом деле, с помощью try-with вообще не нужно закрывать.
Таким образом:
Path tempFile = Paths.get("temp.txt");
Path saveFile = Paths.get("save.txt");
try (
Writer fw = Files.newBufferedWriter(tempFile, StandardOpenOption.APPEND);
BufferedReader br = Files.newBufferedReader(saveFile);
) {
String line;
while ((line = br.readLine()) != null) {
if (line.equals(player.username)) continue;
fw.write(line);
fw.write("\n");
}
}
Files.delete(saveFile);
Files.move(tempFile, saveFile);
Спасибо за ответ, но как мне создать новый файл с java.nio.package, потому что я хочу создать новый временный файл, не получая существующий файл temp.txt
Так же, как вы делаете сегодня. File
— это не файл, это структура данных, содержащая представление пути к файлу. Я не вижу сильного принуждения полностью избегать File
— просто не вызывайте его методы, которые на самом деле делают что-то с файловой системой. Но обратите внимание, вам не нужен File
, чтобы создать FileWriter
.
@ArfurNarf Если вы относитесь к File как к средству для пути и игнорируете практически все его методы, то..... почему бы не использовать String? Или, если вы (правильно) предпочитаете тип, который более подробно описывает то, что он содержит, что может сделать File, чего не может Path, кроме того, что вы не должны делать с File?
@nipeng Если вам нужен новый временный файл, Files.newBufferedWriter(path, StandardOpenOption.CREATE_NEW)
гарантирует, что он новый (выбрасывает, если это не так), и Files.createTempFile
создает новые файлы, выбирая для вас случайные имена, чтобы гарантировать их уникальность.
Хорошо, спасибо за все ответы, которые я пробовал, но используя `Files.createFile(tempFile); ` тоже хорошо. теперь проблема в том, что я получаю файл ошибки, который используется другим процессом, я даже не открывал файл
Вы уверены? Вероятно, это ваш собственный процесс. Код вашего примера неправильно закрывает ресурсы (используйте синтаксис try(...)
).
Я почти уверен, что уже завершил весь процесс отладки, а также уже использую синтаксис try. Созданный временный файл работает нормально, но выдает file is being used by another process
, когда достигает Files.delete
.
@rzwitserloot "тогда..... почему бы не использовать String?" -- В таком случае, почему бы и нет? Я ответил с позиции, что не могу переписать весь огромный корпус кода, с которым мне нужно взаимодействовать. Построение пути только для вызова toFile всегда кажется немного глупым.
@ArfurNarf Устаревший / устаревший в словарном смысле не означает «выйти и переписать все его использования сейчас». Просто: ответ SO, который советует использовать это сейчас, неверен, и вам не следует писать новый код с этим материалом. Нет ничего плохого в том, чтобы использовать .toPath()
/ toFile()
для обозначения устаревшего API, который еще не принимает объекты Path.
@nipeng вставьте полный код. Ошибка вам не лжет - она открыта в каком-то процессе. Весьма вероятно, что это ваш код.
Извините за поздний ответ Вот мой код: Path tempFile = Paths.get("temp.txt"); try { Files.newBufferedWriter(tempFile, StandardOpenOption.CREATE_NEW); } catch (IOException e) { // TODO: handle exception } Path saveFile = Paths.get("save.txt"); Path playerFile = Paths.get(player.username + ".txt");
В остальном тот же код try catch, который вы предоставили
Я уже разобрался, спасибо
@nipeng Этот код, который вы только что вставили в комментарий 4 часа назад, не использует try-with, и это именно то, что я вам сказал, является вероятным объяснением. Начните использовать try-with.
Я бы предложил использовать Files.delete вместо File.delete. Преимущество этого заключается в том, что в случае сбоя создается исключение. Ваш файл не будет удален, если он не удаляется сейчас, но, по крайней мере, вы можете узнать, почему. По тем же причинам я бы предложил Files.move вместо File.renameTo.