File.renameTo()
Кажется, что Java проблематична, особенно в Windows. Как говорится в документации API ,
Многие аспекты поведения этого метода по своей сути зависят от платформы: операция переименования может не иметь возможности переместить файл из одной файловой системы в другую, она может быть не атомарной и может не завершиться успешно, если файл с конечным абстрактным путем уже существует. Возвращаемое значение всегда следует проверять, чтобы убедиться, что операция переименования прошла успешно.
В моем случае в рамках процедуры обновления мне нужно переместить (переименовать) каталог, который может содержать гигабайты данных (множество подкаталогов и файлов разного размера). Перемещение всегда выполняется в пределах одного раздела / диска, поэтому нет реальной необходимости физически перемещать все файлы на диске.
Не должно быть никаких файловых блокировок для содержимого перемещаемого каталога, но все же довольно часто renameTo () не выполняет свою работу и возвращает false. (Я просто предполагаю, что, возможно, некоторые блокировки файлов истекают произвольно в Windows.)
В настоящее время у меня есть запасной метод, который использует копирование и удаление, но это отстой, потому что это может занять много времени, в зависимости от размера папки. Я также подумываю просто задокументировать тот факт, что пользователь может перемещать папку вручную, чтобы потенциально не ждать несколько часов. Но «Правильный путь», очевидно, будет чем-то автоматическим и быстрым.
Итак, мой вопрос: знаете ли вы альтернативный, надежный подход для быстрого перемещения / переименования с помощью Java в Windows , либо с помощью простого JDK, либо с помощью какой-либо внешней библиотеки. Или, если вы знаете простой способ обнаружить и снять любые блокировки файлов для данной папки и всего ее содержимого (возможно, тысяч отдельных файлов), это тоже будет хорошо.
Изменить : в этом конкретном случае кажется, что мы ушли от использования, просто renameTo()
приняв во внимание еще несколько вещей; см. этот ответ .
Ответы:
См. Также
Files.move()
метод в JDK 7.Пример:
String fileName = "MyFile.txt"; try { Files.move(new File(fileName).toPath(), new File(fileName).toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); } catch (IOException ex) { Logger.getLogger(SomeClass.class.getName()).log(Level.SEVERE, null, ex); }
источник
Для чего стоит еще несколько понятий:
В Windows
renameTo()
кажется, что не работает, если целевой каталог существует, даже если он пуст. Это меня удивило, так как я пробовал на Linux, где всеrenameTo()
получалось, если цель существовала, пока она была пуста.(Очевидно, я не должен был предполагать, что подобные вещи работают одинаково на разных платформах; это именно то, о чем предупреждает Javadoc.)
Если вы подозреваете, что могут существовать некоторые длительные блокировки файлов, подождите немного, прежде чем перемещение / переименование может помочь. (В какой-то момент в нашем установщике / программе обновления мы добавили действие «сна» и неопределенный индикатор выполнения примерно на 10 секунд, потому что к некоторым файлам может быть привязана служба). Возможно, даже можно использовать простой механизм повтора, который пытается
renameTo()
, а затем ждет в течение определенного периода (который, возможно, постепенно увеличивается), пока операция не завершится успешно или не будет достигнут некоторый тайм-аут.В моем случае большинство проблем, похоже, были решены с учетом обоих вышеперечисленных, поэтому нам не нужно будет выполнять вызов собственного ядра или что-то в этом роде, в конце концов.
источник
В исходном сообщении запрашивался «альтернативный, надежный подход для быстрого перемещения / переименования с помощью Java в Windows, либо с помощью простого JDK, либо с помощью какой-либо внешней библиотеки».
Другой вариант, еще не упомянутый здесь, - это библиотека apache.commons.io v1.3.2 или новее , которая включает FileUtils.moveFile () .
Он генерирует исключение IOException вместо возврата логического значения false при ошибке.
См. Также ответ big lep в этой другой ветке .
источник
java.nio.file.Path.moveTo()
В моем случае это выглядело как мертвый объект в моем собственном приложении, хранящем дескриптор этого файла. Итак, это решение сработало для меня:
for (int i = 0; i < 20; i++) { if (sourceFile.renameTo(backupFile)) break; System.gc(); Thread.yield(); }
Преимущество: это довольно быстро, поскольку нет Thread.sleep () с определенным жестко заданным временем.
Недостаток: ограничение в 20 - это жестко запрограммированное число. Во всех моих тестах достаточно i = 1. Но на всякий случай оставил на 20.
источник
Я знаю, что это кажется немного взломанным, но для того, что мне было нужно, кажется, что у буферизованных читателей и писателей нет проблем с созданием файлов.
void renameFiles(String oldName, String newName) { String sCurrentLine = ""; try { BufferedReader br = new BufferedReader(new FileReader(oldName)); BufferedWriter bw = new BufferedWriter(new FileWriter(newName)); while ((sCurrentLine = br.readLine()) != null) { bw.write(sCurrentLine); bw.newLine(); } br.close(); bw.close(); File org = new File(oldName); org.delete(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
Хорошо работает для небольших текстовых файлов как часть анализатора, просто убедитесь, что oldName и newName - это полные пути к расположению файлов.
Ура Кактус
источник
Следующий фрагмент кода НЕ является альтернативой, но надежно работал у меня как в среде Windows, так и в среде Linux:
public static void renameFile(String oldName, String newName) throws IOException { File srcFile = new File(oldName); boolean bSucceeded = false; try { File destFile = new File(newName); if (destFile.exists()) { if (!destFile.delete()) { throw new IOException(oldName + " was not successfully renamed to " + newName); } } if (!srcFile.renameTo(destFile)) { throw new IOException(oldName + " was not successfully renamed to " + newName); } else { bSucceeded = true; } } finally { if (bSucceeded) { srcFile.delete(); } } }
источник
В Windows я использую,
Runtime.getRuntime().exec("cmd \\c ")
а затем использую функцию переименования в командной строке, чтобы фактически переименовывать файлы. Это гораздо более гибко, например, если вы хотите переименовать расширение всех файлов txt в каталоге в bak, просто напишите это в выходной поток:переименовать * .txt * .bak
Я знаю, что это не очень хорошее решение, но, видимо, оно всегда работало для меня, намного лучше, чем встроенная поддержка Java.
источник
Почему нет....
import com.sun.jna.Native; import com.sun.jna.Library; public class RenamerByJna { /* Requires jna.jar to be in your path */ public interface Kernel32 extends Library { public boolean MoveFileA(String existingFileName, String newFileName); } public static void main(String[] args) { String path = "C:/yourchosenpath/"; String existingFileName = path + "test.txt"; String newFileName = path + "renamed.txt"; Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class); kernel32.MoveFileA(existingFileName, newFileName); } }
работает на nwindows 7, ничего не делает, если файл existingFile не существует, но, очевидно, можно было бы лучше исправить это.
источник
У меня была аналогичная проблема. Файл копировался довольно подвижно в Windows, но хорошо работал в Linux. Я исправил проблему, закрыв открытый fileInputStream перед вызовом renameTo (). Проверено на Windows XP.
fis = new FileInputStream(originalFile); .. .. .. fis.close();// <<<---- Fixed by adding this originalFile.renameTo(newDesitnationForOriginalFile);
источник
В моем случае ошибка была в пути к родительскому каталогу. Возможно ошибка, мне пришлось использовать подстроку, чтобы получить правильный путь.
try { String n = f.getAbsolutePath(); **n = n.substring(0, n.lastIndexOf("\\"));** File dest = new File(**n**, newName); f.renameTo(dest); } catch (Exception ex) { ...
источник
Я знаю, что это отстой, но альтернативой является создание сценария летучей мыши, который выводит что-то простое, например «УСПЕХ» или «ОШИБКА», вызывает его, ожидает его выполнения и затем проверяет его результаты.
Runtime.getRuntime (). Exec ("cmd / c start test.bat");
Эта ветка может быть интересной. Также проверьте класс Process, чтобы узнать, как читать вывод консоли другого процесса.
источник
Вы можете попробовать robocopy . Это не совсем "переименование", но очень надежно.
источник
Чтобы переместить / переименовать файл, вы можете использовать эту функцию:
BOOL WINAPI MoveFile( __in LPCTSTR lpExistingFileName, __in LPCTSTR lpNewFileName );
Он определен в kernel32.dll.
источник
File srcFile = new File(origFilename); File destFile = new File(newFilename); srcFile.renameTo(destFile);
Выше приведен простой код. Я тестировал Windows 7 и отлично работает.
источник