Как определить, будет ли файл перемещен логически или физически - PullRequest
1 голос
/ 10 апреля 2009

Факты:

Когда файл перемещается, есть две возможности:

  1. Исходный и целевой файлы находятся в одном разделе, и обновляется только индекс файловой системы
  2. Источник и место назначения находятся в двух разных файловых системах, и файл необходимо перемещать байт за байт. (он же копия на ходу)

Вопрос:

Как определить, будет ли файл перемещен логически или физически?

Я передаю большие файлы (более 700 мегабайт), и для каждой ситуации будет применяться другое поведение.


Edit:

Я уже закодировал диалог перемещения файла с рабочим потоком, который выполняет блокирующий вызов io, чтобы скопировать файл по мегабайту за раз. Он предоставляет информацию пользователю в виде приблизительной оценки оставшегося времени и скорости передачи.

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

Ответы [ 2 ]

4 голосов
/ 10 апреля 2009

В Linux или других * приложениях вызовите stat() в исходном и целевом каталогах и сравните их значения st_dev. Если они совпадают, может быть выполнен логический ход, в противном случае необходимо выполнить физическое копирование + удаление.

В Windows вы можете вызвать GetFileInformationByHandle() на дескрипторах двух каталогов и сравнить их значения dwVolumeSerialNumber. Обратите внимание, что для этого требуется Windows 2000 или более поздняя версия.

Я вижу, что вы используете Java - должен быть какой-то портал, через который вы можете получить доступ к этой информации уровня ОС (возможно, JNI?)

2 голосов
/ 10 апреля 2009

Хорошо, я о чем-то:)

Использование JNA Я могу вызвать Win32 API (и * nix API тоже) из java .

Я попытался вызвать GetFileInformationByHandle и получил результат, НО атрибут dwVolumeSerialNumber всегда равен 0 (пробовал с моим диском C: и D:)

Тогда я увидел эту функцию на MSDN: MoveFileEx. Когда параметр флага установлен на 0, функция копирования при перемещении будет отключена. И ЭТО РАБОТАЕТ !!!!

Так что я просто позвоню

if (!Kernel32.INSTANCE.MoveFileEx(source.getAbsolutePath(), destination.getAbsolutePath(), 0)) {
    System.out.println("logical move failed");
}

Вот код, который нужно вставить в интерфейс Kernel32.java (этот файл можно найти в пакете src.zip в разделе загрузки на сайте JNA ):

boolean MoveFileEx(String lpExistingFileName, String lpNewFileName, int dwFlags);

int MOVEFILE_REPLACE_EXISTING = 0x01;
int MOVEFILE_COPY_ALLOWED = 0x02;
int MOVEFILE_CREATE_HARDLINK = 0x04;
int MOVEFILE_WRITE_THROUGH = 0x08;
int MOVEFILE_DELAY_UNTIL_REBOOT = 0x10;
int MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20;
...