The facts:
When a file is moved, there's two possibilities:
- The source and destination file are on the same partition and only the file system index is updated
- The source and destination are on two different file system and the file need to be moved byte per byte. (aka copy on move)
The question:
How can I determine if a file will be either logically or physically moved ?
I'm transferring large files (700+ megs) and would adopt a different behaviors for each situation.
Edit:
I've already coded a moving file dialog with a worker thread that perform the blocking io call to copy the file a meg at a time. It provide information to the user like rough estimate of the remaining time and transfer rate.
The problem is: how do I know if the file can be moved logically before trying to move it physically ?
-
On Linux or other *nices, call
stat()on the source and destination directories and compare theirst_devvalues. If they are the same, a logical move can be performed, otherwise a physical copy+delete must be performed.On Windows, you can call
GetFileInformationByHandle()on handles to the two directories and compare theirdwVolumeSerialNumbervalues. Note that this requires Windows 2000 or later.I see you're using Java -- there must be some portal through which you can access this OS-level info (perhaps JNI?)
Frederic Morin : Wow, impressive :) I'll try to find more information about that. Thank you !j_random_hacker : I hope it helps, but I can't guarantee that these conditions will hold -- it just makes sense that they would ;)Frederic Morin : Oh, I see. I'm currently looking toward JNA (https://jna.dev.java.net/) for kernel32 and unix API access.Frederic Morin : Is it ok for you if I accept my own answer ?j_random_hacker : @Blade: By all means, it's the answer that worked for you! :) -
Ok I'm on something :)
Using JNA I am able to call the Win32 API (and *nix API too) from java.
I tried calling
GetFileInformationByHandleand did got a result BUT thedwVolumeSerialNumberattribute always equals 0 (tried with my C: and D: drive)Then I saw this function on MSDN:
MoveFileEx. When the flag parametter is set to 0, the copy on move feature will be disable. AND IT WORKS !!!!So I will simply call
if (!Kernel32.INSTANCE.MoveFileEx(source.getAbsolutePath(), destination.getAbsolutePath(), 0)) { System.out.println("logical move failed"); }Here is the code to put in the
Kernel32.javainterface (this file can be found in the src.zip package in the download section of the JNA site):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;j_random_hacker : +1, MoveFileEx() is a good find. I'm curious though: how are you getting the HANDLE value to call GetFileInformationByHandle() with? The dwVolumeSerialNumber entry is populated sensibly in my C++ test program (i.e. it's a nonzero value, different for different drives).Frederic Morin : I got it using CreateFile wich return a file handle. When you call CreateFile, you have to specify that a new file must not be created so it will fail if the file does not exist.j_random_hacker : Hmm... CreateFile() is the right way to get a HANDLE, but I'm a bit puzzled as to why you talked about specifying that a new file must not be created -- are you possibly trying to open the destination *file* (which doesn't exist yet), instead of the destination *directory*?Frederic Morin : Actually, I was comparing two files on two differents disks so for my little test, I didin't want to create a new file. But you're right, in the case we are interested in, it would make sense to create the target file at this stage.
0 comments:
Post a Comment