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

Факты:

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

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

Вопрос:

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

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


Редактировать:

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

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


person Frederic Morin    schedule 10.04.2009    source источник
comment
Вы делаете ошибочное предположение, что перемещение файла в тот же раздел — это просто изменение метаданных. Это не обязательно верно для NTFS. Перемещение файла в сжатый каталог или из него может привести к тому, что физическая копия (де)сожмет файл. Точно так же зашифрованные каталоги могут привести к тому, что физические копии будут (де)шифровать файл.   -  person MSalters    schedule 16.09.2009
comment
Вы правы, может потребоваться операция копирования/удаления в пределах одного и того же раздела NTFS. Но, тем не менее, моя цель состояла в том, чтобы определить, потребуется ли копирование/удаление или простое изменение метаданных поможет переместить файл. Принятое решение решает эту проблему. Если у вас есть другие вопросы или другие решения, не стесняйтесь вносить свой вклад. Спасибо   -  person Frederic Morin    schedule 21.09.2009


Ответы (2)


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

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

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

person j_random_hacker    schedule 10.04.2009
comment
Вау, впечатляет :) Постараюсь найти больше информации об этом. Спасибо ! - person Frederic Morin; 10.04.2009
comment
Я надеюсь, что это поможет, но я не могу гарантировать, что эти условия будут соблюдаться — просто логично, что они будут соблюдаться ;) - person j_random_hacker; 10.04.2009
comment
О, я вижу. В настоящее время я ищу JNA (jna.dev.java.net) для API ядра 32 и unix. доступ. - person Frederic Morin; 10.04.2009
comment
@Blade: Во что бы то ни стало, это ответ, который сработал для вас! :) - person j_random_hacker; 14.04.2009

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

Используя JNA, я могу вызвать Win32 API< /strong> (и *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;
person Frederic Morin    schedule 10.04.2009
comment
+1, MoveFileEx() - хорошая находка. Мне любопытно: как вы получаете значение HANDLE для вызова GetFileInformationByHandle()? Запись dwVolumeSerialNumber разумно заполняется в моей тестовой программе на C++ (т. е. это ненулевое значение, разное для разных дисков). - person j_random_hacker; 11.04.2009
comment
Я получил его с помощью CreateFile, который возвращает дескриптор файла. Когда вы вызываете CreateFile, вы должны указать, что новый файл не должен создаваться, поэтому если файл не существует, произойдет сбой. - person Frederic Morin; 12.04.2009
comment
Хм... CreateFile() - это правильный способ получить HANDLE, но я немного озадачен тем, почему вы говорили об указании того, что новый файл не должен создаваться - возможно, вы пытаетесь открыть место назначения файл (которого еще не существует) вместо целевого каталога? - person j_random_hacker; 12.04.2009
comment
На самом деле, я сравнивал два файла на двух разных дисках, поэтому для своего небольшого теста я не хотел создавать новый файл. Но вы правы, в интересующем нас случае имело бы смысл создать целевой файл на этом этапе. - person Frederic Morin; 13.04.2009