85

Вопрос по file-io, file, java, windows – undefined

Java & APOS; sFile.renameTo() проблематично, особенно на винде, кажется. КакAPI документация говорит,

Many aspects of the behavior of this method are inherently platform-dependent: The rename operation might not be able to move a file from one filesystem to another, it might not be atomic, and it might not succeed if a file with the destination abstract pathname already exists. The return value should always be checked to make sure that the rename operation was successful.

В моем случае, как часть процедуры обновления, мне нужно переместить (переименовать) каталог, который может содержать гигабайты данных (множество подкаталогов и файлов разных размеров). Перемещение всегда выполняется в пределах одного раздела / диска, поэтому нет реальной необходимости физически перемещать все файлы на диске.

Тамshouldn't Если какой-либо файл блокирует содержимое каталога, который нужно переместить, но все же довольно часто renameTo () не выполняет свою работу и возвращает false. (Я просто предполагаю, что, возможно, некоторые блокировки файлов в Windows истекают произвольно.)

В настоящее время у меня есть запасной метод, который использует копирование & amp; удаление, но это отстой, потому что это может занятьa lot времени, в зависимости от размера папки. Я также рассматриваю просто документирование того факта, что пользователь может перемещать папку вручную, чтобы избежать ожидания в течение нескольких часов. Но «Правильный путь» очевидно был бы чем-то автоматическим и быстрым.

Итак, мой вопрос,do you know an alternative, reliable approach to do a quick move/rename with Java on Windowsлибо с простым JDK, либо с какой-нибудь внешней библиотекой. Или если вы знаетеeasy способ обнаружить и снять любые блокировки файлов для данной папки иall of its contents (возможно, тысячи отдельных файлов), это тоже будет хорошо.


Edit: В данном конкретном случае кажется, что мы ушли, используя толькоrenameTo() принимая во внимание еще несколько вещей; увидетьэтот ответ.

  • Error: User Rate Limit Exceedednot работать надежно; в этом весь смысл вопроса.

    от Jonik
  • Error: User Rate Limit Exceeded

    от Jonik
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceededjohannburkard.de/software/nativecallError: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit ExceededJDK 7 answerError: User Rate Limit Exceeded

    от Jonik
  • Error: User Rate Limit Exceeded

    от Jonik
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceededjava.nio.file.Path.moveTo()

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceededjava.sun.com/javase/7/docs/api/java/nio/file/Path.html

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Jonik
  • Error: User Rate Limit Exceededstackoverflow.com/questions/1000723/…

    от Jonik
  • @Jonik, Thanx, исправлен код, который не удалял файл src в случае неудачного переименования.

    от
  • Спасибо, что поделились этим, исправили мою проблему с переименованием в Windows.

    от
  • @ kd304, на самом деле я не могу ждать или использовать версию с ранним доступом, но интересно узнать, что-то подобное уже в пути!

    от Jonik
  • Вы можете подождать / использовать JDK 7, который имеет гораздо лучшую поддержку файловой системы.

    от akarnokd
14 ответов
  • 4

    Следующий фрагмент кода НЕ является «альтернативой» но надежно работал

    для меня как в среде Windows, так и в Linux:

    public static void renameFile(String oldName, String newName) throws IOException {
        File srcFile = new File(oldNam,e);
        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();
              }
        }
    }
    

  • -8

    Выше простой код. Я проверил на Windows 7 и работает отлично.

     File srcFile = new File(origFilename);
     File destFile = new File(newFilename);
     srcFile.renameTo(destFile);
    

  • -2

    Для перемещения / переименования файла вы можете использовать эту функ

    цию:

    BOOL WINAPI MoveFile(
      __in  LPCTSTR lpExistingFileName,
      __in  LPCTSTR lpNewFileName
    );
    

    Это определяется в kernel32.dll.

  • 45

    Смотрите также

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

  • 1

    В моем случае ошибка была в пути к родительскому каталогу. Возможно

    ошибка, мне пришлось использовать подстроку, чтобы получить правильный путь.

            try {
                String n = f.getAbsolutePath();
                **n = n.substring(0, n.lastIndexOf("\\"));**
                File dest = new File(**n**, newName);
                f.renameTo(dest);
            } catch (Exception ex) {
               ...
    

  • 1

    У меня была похожая проблема. Файл был скопирован в Windows

    но хорошо работал в Linux. Я исправил проблему, закрыв открытый fileInputStream перед вызовом renameTo (). Проверено на Windows XP.

    fis = new FileInputStream(originalFile);
    ..
    ..
    ..
    fis.close();// <<<---- Fixed by adding this
    originalFile.renameTo(newDesitnationForOriginalFile);
    

  • 19

    В первоначальной публикации запрашивался «альтернативный

    надежный подход для быстрого перемещения / переименования с помощью Java в Windows, с использованием простого JDK или некоторой внешней библиотеки».

    Еще один вариант, не упомянутый здесь, v1.3.2 или новееapache.commons.io библиотека, которая включает в себяFileUtils.moveFile ().

    Он выдает IOException вместо возврата логического false в случае ошибки.

    Смотрите такжеbig lepответ вэтот другой поток.

  • 3

    Я знаю

    что это выглядит немного странно, но для того, для чего я нуждался, кажется, что у читателей и писателей нет проблем с созданием файлов.

    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 являются полными путями к расположению файлов.

    ура Kactus

  • 1

    Почему бы и нет....

    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, ничего не делает, если существующий файл не существует, но, очевидно, может быть лучше приспособлен, чтобы это исправить.

  • 0

    Я знаю

    что это отстой, но альтернативой является создание сценария bat, который выводит что-то простое, например & quot; SUCCESS & quot; или «ОШИБКА», вызовите его, дождитесь его выполнения и затем проверьте его результаты.

    Runtime.getRuntime (). Exec (& quot; cmd / c start test.bat & quot;);

    Эта тема может быть интересной. Также проверьте класс Process, как прочитать вывод консоли другого процесса.

  • 2

    На окнах я использую

    Runtime.getRuntime().exec("cmd \\c ") а затем использовать функцию переименования командной строки, чтобы фактически переименовать файлы. Это гораздо более гибко, например, если вы хотите переименовать расширение всех текстовых файлов в директории bak, просто запишите это в выходной поток:

    переименовать * .txt * .bak

    Я знаю, что это не очень хорошее решение, но, очевидно, оно всегда работало для меня, намного лучше, чем встроенная поддержка Java.

  • 25

    Для чего стоит еще несколько понятий:

    On Windows, renameTo() seems to fail if the target directory exists, even if it's empty. This surprised me, as I had tried on Linux, where renameTo() succeeded if target existed, as long as it was empty.

    (Obviously I shouldn't have assumed this kind of thing works the same across platforms; this is exactly what the Javadoc warns about.)

    If you suspect there may be some lingering file locks, waiting a little before the move/rename might help. (In one point in our installer/upgrader we added a "sleep" action and an indeterminate progress bar for some 10 seconds, because there might be a service hanging on to some files). Perhaps even do a simple retry mechanism that tries renameTo(), and then waits for a period (which maybe increases gradually), until the operation succeeds or some timeout is reached.

    В моем случае большинство проблем, по-видимому, было решено с учетом обоих вышеперечисленных факторов, поэтому нам, в конце концов, не нужно будет выполнять вызов ядра или что-то подобное.

  • 4

    В моем случае это был мертвый объект в моем собственном приложении

    который хранил дескриптор этого файла. Так что это решение сработало для меня:

    for (int i = 0; i < 20; i++) {
        if (sourceFile.renameTo(backupFile))
            break;
        System.gc();
        Thread.yield();
    }
    

    Преимущество: это довольно быстро, так как нет Thread.sleep () с определенным жестко заданным временем.

    Недостаток: этот предел в 20 является каким-то жестко закодированным числом. Во всех моих тестах i = 1 достаточно. Но чтобы быть уверенным, я оставил это в 20.

  • -2

    Вы можете попробовать

    Robocopy, Это не совсем «переименование», но это очень надежно.

    Robocopy is designed for reliable mirroring of directories or directory trees. It has features to ensure all NTFS attributes and properties are copied, and includes additional restart code for network connections subject to disruption.