【问题标题】:How to determine if a file will be logically moved or physically moved如何确定文件是逻辑移动还是物理移动
【发布时间】:2009-04-10 06:14:32
【问题描述】:

事实:

当文件被移动时,有两种可能:

  1. 源文件和目标文件在同一个分区,只更新文件系统索引
  2. 源和目标位于两个不同的文件系统上,文件需要逐字节移动。 (又名移动复制)

问题:

如何确定文件是逻辑移动还是物理移动?

我正在传输大文件(700 多兆),并且会针对每种情况采取不同的行为。


编辑:

我已经编写了一个带有工作线程的移动文件对话框,该线程执行阻塞 io 调用以一次复制一个文件。它向用户提供信息,例如粗略估计剩余时间和传输速率。

问题是:我如何知道文件是否可以在尝试物理移动之前进行逻辑移动?

【问题讨论】:

  • 您错误地假设文件在同一分区上移动仅仅是元数据的更改。在 NTFS 上不一定如此。将文件移入或移出压缩目录可能会导致物理副本(解压缩)文件。同样,加密目录可能会导致物理副本(解密)文件。
  • 您是对的,在同一个 NTFS 分区中可能需要进行复制/删除操作。但是,我的目标仍然是确定是否需要复制/删除或简单的元数据更改来完成移动文件的工作。公认的解决方案解决了这个问题。如果您有其他问题或其他解决方案,请随时贡献。谢谢

标签: java file-io filesystems nio


【解决方案1】:

在 Linux 或其他 *nices 上,在源目录和目标目录上调用 stat() 并比较它们的 st_dev 值。如果相同,则可以进行逻辑移动,否则必须进行物理复制+删除。

在 Windows 上,您可以在两个目录的句柄上调用 GetFileInformationByHandle() 并比较它们的 dwVolumeSerialNumber 值。请注意,这需要 Windows 2000 或更高版本。

我看到您使用的是 Java —— 必须有一些门户网站,您可以通过该门户网站访问此操作系统级别的信息(可能是 JNI?)

【讨论】:

  • 哇,令人印象深刻 :) 我会尝试找到有关此的更多信息。谢谢!
  • 我希望它有所帮助,但我不能保证这些条件会成立——它们会成立是有道理的 ;)
  • 哦,我明白了。我目前正在寻找 JNA (jna.dev.java.net) 以获取 kernel32 和 unix API 访问权限。
  • @Blade:无论如何,这是对你有用的答案! :)
【解决方案2】:

好的,我正在做某事:)

使用 JNA 我可以从 java调用 Win32 API(和 *nix API)

我尝试调用 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接口的代码(这个文件可以在JNA网站下载部分的src.zip包中找到):

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;

【讨论】:

  • +1,MoveFileEx() 是一个不错的发现。不过我很好奇:你是如何获得 HANDLE 值来调用 GetFileInformationByHandle() 的? dwVolumeSerialNumber 条目在我的 C++ 测试程序中被合理填充(即它是一个非零值,不同驱动器不同)。
  • 我使用 CreateFile 得到它,它返回一个文件句柄。当你调用 CreateFile 时,你必须指定一个新文件不能被创建,这样如果文件不存在就会失败。
  • Hmm... CreateFile() 是获取 HANDLE 的正确方法,但我有点困惑为什么您谈到指定不得创建新文件——您是可能试图打开目标 file(尚不存在),而不是目标 directory
  • 实际上,我正在比较两个不同磁盘上的两个文件,所以对于我的小测试,我不想创建一个新文件。但你说得对,在我们感兴趣的情况下,在这个阶段创建目标文件是有意义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-22
相关资源
最近更新 更多