Основные библиотеки Java не предсказывают случай «циклического копирования» файла в место назначения, иначе сопоставленное - PullRequest
2 голосов
/ 14 февраля 2012

По своему опыту и после неоднократных тестов, проведенных мной и глубоких веб-исследований, я обнаружил, что основные библиотеки java ("Apache Commons", Google.coomons или Jcifs) не предсказывают случай "циклического копирования".»Файла в место назначения, которое по-разному отображается (обозначается с помощью другого RootPath в соответствии с более новым пакетом Path Class класса java.nio), которое в конце цикла отображения преобразуется в сам исходный файл.

Это ситуацияпотеря данных, потому что метод Outputsream и метод GetChannel jnio не позволяют себе в этом случае: исходный файл и конечный файл в действительности являются «одним и тем же файлом», и результатом этих методов является то, что файл теряется, лучше сказать, что размер файла становитсяДлина 0.

Как можно избежать этого, не выходя на более низкий уровень файловой системы или даже не сдаваясь более безопасному Runtime.exec, делегируя вещи в базовый SO

Если мне придетсязаблокировать файл назначения (описанные выше методы не позволяют этого), возможнос помощью самого старого класса RandomAccessFile?

Вы можете протестировать эти цитированные основные библиотеки с помощью общего метода "CopyFile (File origin, File dest)", выполнив:

1)исходная папка файла c: \ tmp \ test.txt, сопоставленная с виртуальным диском x: с помощью [SUBST x: c: \ tmp] cmd, таким образом, пытающаяся скопировать в x: \ test.txt

2)Аналогичный случай, если локальная папка c: \ tmp была открыта для общего доступа с помощью механизма общего доступа Windows, а место назначения представлено в виде пути UNC, заканчивающегося тем же именем файла

3) Другие аналогичные сетевые ситуации ...

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

Ответы [ 4 ]

0 голосов
/ 16 февраля 2012

Спасибо за обращение от других опытных членов сообщества, а также благодаря молодому члену моей команды, Тиндаро, который помог мне в исследовании, я нашел реальное решение в JDK 1.7, которое сделано Надежный, быстрый, простой и почти наверняка вызовет жалкую завесу на старых решениях java.io. Несмотря на то, что в Интернете все еще полно примеров копирования файлов в Java с использованием In / Out Streams, я настоятельно рекомендую всем использовать простой метод: java.nio.Files.copy (Происхождение пути, Назначение пути) с дополнительными параметрами для замены места назначения, переноса атрибутов файла метаданных и даже попытки транзакционного перемещения файлов (если это разрешено базовой ОС). Это действительно хорошая работа, которую так долго ждали! Вы можете легко преобразовать код из копии (Файл file1, Файл file2), добавив «.toPath ()» к экземпляру File (например, file1.toPath (), file2.toPath () . Также обратите внимание, что логический метод " isSameFile (file1.toPath (), file2.toPath ()) " уже используется внутри вышеуказанного метода копирования, но его легко использовать в любом случае. Для каждого случая, когда вы не можете выполнить обновление до 1.7, по-прежнему рекомендуется использовать библиотеки сообщества из Apache или Google, но для надежной цели позвольте мне предложить временный обходной путь, который я нашел ранее:

public static boolean isTheSameFile(File f1, File f2) {//throws Exception{
    // minimum prerequisites !
    if(f1.length()!=f2.length()) return false; 
    if (!file1.exists() || !file2.exists()) { return false; }
    if (file1.isDirectory() || file2.isDirectory()){ return false; }
    //if (file1.getCanonicalFile().equals(file2.getCanonicalFile())); //don't rely in this ! can even still fail 
    //new FileInputStream(f2).getChannel().lock();//exception, can lock only on OutputStream
    RandomAccessFile rf1=null,rf2=null; //the only practicable solution on my own ... better than parse entire files
    try {
        rf1 = new RandomAccessFile(f1, "r");
        rf2=new RandomAccessFile(f2, "rw");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        return false;
    }

    try {
        rf2.getChannel().lock();
    } catch (IOException e) {
        return false;
    }

    try {
        rf1.getChannel().read(ByteBuffer.allocate(1));//reads 1 only byte
    } catch (IOException e) {
        //e.printStackTrace(); // if and if only the same file, the O.S. will throw an IOException with reason "file already in use"
        try {rf2.close();} catch (IOException e1) {}
        return true;
    }
    //close the still opened resources ...
    if (rf1.getChannel().isOpen())
        try {rf1.getChannel().close();} catch (IOException e) {}

    try {
        rf2.close();
    } catch (IOException e) {
        return false;
    }
    // done, files differs
    return false;
}
0 голосов
/ 14 февраля 2012

Возможно, вы можете попытаться подойти к этой проблеме немного по-другому и попытаться определить, совпадают ли исходные и целевые файлы, сравнив метаданные файла (имя, размер, дату и т. Д.) И, возможно, даже вычислить хэш содержимого файлов.Это, конечно, замедлит обработку.

Если у вас достаточно прав, вы также можете написать «маркерный» файл со случайным именем в месте назначения и попытаться прочитать его в источнике, чтобы определить, что они указывают на одно и то же место.Или попробуйте проверить, что файл уже существует в месте назначения перед копированием.

0 голосов
/ 15 февраля 2012

Я согласен, что это необычные ситуации, но вы согласитесь, что файлы являются критически важной базой любой ИТ-системы. Я не согласен с тем, что манипулирование файлами в java является необычным: в моем случае я должен прикрепить файлы изображений продуктов через FileChooser и скопировать их заказным способом в репозиторий ... но пользователи реального мира (назовите их покупателями, которые покупают ваш продукт) могут упасть в таких ситуациях и если это произойдет, нельзя обвинять дьявола в неудаче, если ваш продукт делает что-то «меньше», чем ожидалось. Это хорошая практика - учиться на собственном опыте и стараться избегать того, что гласит один из законов Мерфи, более или менее: «если что-то МОЖЕТ пойти не так, рано или поздно это может пойти не так. Возможно, это также одна из причин, по которой я считаю, что команда Java в Sun и Oracle усовершенствовала старый пакет java.io для самого нового java.nio. Я анализирую новый класс java.nio.Files, на который я обратил внимание, и вскоре я верю, что нашел решение, которое хотел и ожидал. Увидимся позже.

0 голосов
/ 14 февраля 2012

Ваш вопрос интересный, никогда не задумывался об этом. Посмотрите на этот вопрос: Определите символические ссылки . Вы должны определить цикл перед копированием.

...