Java NTFS压缩属性

Java NTFS压缩属性,java,ntfs,file-attributes,Java,Ntfs,File Attributes,我需要从Java读取并修改NTFS分区上文件的“Compressed”属性。我想象包中的某些东西可以做到这一点——见鬼,这是一个足够复杂的包,但我找不到这个属性 DosFileAttributes类只有经典的hidden/system/readonly/archive属性的getter 我尝试了从特定的“属性视图”中动态检索所有属性。在“dos:*”下,只有与DosFileAttributes类的公共方法相同的属性可用。我尝试了“ntfs:*”和“windows:*”,但它们不能作为有效的视图名

我需要从Java读取并修改NTFS分区上文件的“Compressed”属性。我想象包中的某些东西可以做到这一点——见鬼,这是一个足够复杂的包,但我找不到这个属性

DosFileAttributes
类只有经典的hidden/system/readonly/archive属性的getter

我尝试了从特定的“属性视图”中动态检索所有属性。在“dos:*”下,只有与
DosFileAttributes
类的公共方法相同的属性可用。我尝试了“ntfs:*”和“windows:*”,但它们不能作为有效的视图名称

我还尝试了
UserDefinedFileAttributeView
,但它在我尝试的任何文件上都给了我一个空列表


我想知道如何使用这个命令(接受它对在Linux或其他操作系统下安装的NTFS分区不起作用的限制),但它似乎也不支持这个属性。帮助?

尝试使用BasicFileAttributes并检查isOther()和isRegularFile()标志,而不是DosFileAttributes。这可能会告诉您文件是否已压缩。如果没有,您将不得不为NTFS创建自己的FileSystemProvider impl,或者编写小型JNI代码,使用WinAPI为您读取该标志。

由于标准Java API中似乎缺少这一点,因此我考虑自己做这件事。这是我第一次体验JNA。它并没有我所希望的那么漂亮,JNA的代码似乎非常缺乏泛型,但这比玩弄JNI并试图为所需的不同平台设置糟糕的交叉编译器要好一百倍(即使您只针对一个操作系统,也至少需要x86和x64)。这是一个恼人的编译过程,首先把我从C++驱动到java,我希望永远不要返回它。 不管怎样,这似乎奏效了。希望它对其他人也有用。它提供了四种公共方法:

  • isAvailable()
    ——调用其他方法是否可行(即,我们在Windows上,JNA本机库加载正常)
  • isCompressed(文件)
  • setCompressed(文件,布尔值)
  • 卷支持文件压缩(文件)
    ——询问Windows文件所在的分区是否支持[单个]文件压缩。例如,在NTFS上为真,在FAT(U盘等)上为假
Windows API中的压缩通过专用I/O控制操作完成,而不仅仅是“SetAttributes”调用。如果它更简单(与其他文件属性同构),出于完整性考虑,我也会将加密属性放在其中,但无论如何

import java.io.File;
import java.io.IOException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.ShortByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT.HANDLE;

public class WindowsFileOps {
    private WindowsFileOps() {}


    private static interface Kernel32Extra extends StdCallLibrary {
        int COMPRESSION_FORMAT_NONE = 0x00000000;
        int COMPRESSION_FORMAT_DEFAULT = 0x00000001;
        int FSCTL_SET_COMPRESSION = 0x0009C040;

        Kernel32Extra INSTANCE = (Kernel32Extra)Native.loadLibrary("kernel32",
            Kernel32Extra.class, W32APIOptions.UNICODE_OPTIONS);

        boolean GetVolumeInformation(
            String lpRootPathName,
            Pointer lpVolumeNameBuffer,
            int nVolumeNameSize,
            IntByReference lpVolumeSerialNumber,
            IntByReference lpMaximumComponentLength,
            IntByReference lpFileSystemFlags,
            Pointer lpFileSystemNameBuffer,
            int nFileSystemNameSize
        );
    }


    private static Boolean isAvailable;
    public static boolean isAvailable() {
        if (isAvailable == null) {
            try {
                isAvailable = Kernel32.INSTANCE != null && Kernel32Extra.INSTANCE != null;
            } catch (Throwable t) {
                isAvailable = false;
            }
        }
        return isAvailable;
    }


    private static String pathString(File file) {
        // "\\?\" is a Windows API thing that enables paths longer than 260 chars
        return "\\\\?\\" + file.getAbsolutePath();
    }


    private static int getAttributes(File file) throws IOException {
        int attrib = Kernel32.INSTANCE.GetFileAttributes(pathString(file));
        if (attrib == Kernel32.INVALID_FILE_ATTRIBUTES) {
            throw new IOException("Unable to read file attributes of " + file);
        }
        return attrib;
    }


    public static boolean isCompressed(File file) throws IOException {
        return (getAttributes(file) & Kernel32.FILE_ATTRIBUTE_COMPRESSED) != 0;
    }


    public static void setCompressed(File file, boolean compressed) throws IOException {
        HANDLE hFile = Kernel32.INSTANCE.CreateFile(
            pathString(file),
            Kernel32.GENERIC_READ | Kernel32.GENERIC_WRITE,
            Kernel32.FILE_SHARE_READ,
            null,
            Kernel32.OPEN_EXISTING,
            0,
            null);
        try {
            if (!Kernel32.INSTANCE.DeviceIoControl(
                hFile,
                Kernel32Extra.FSCTL_SET_COMPRESSION,
                new ShortByReference((short)(
                    compressed
                        ? Kernel32Extra.COMPRESSION_FORMAT_DEFAULT
                        : Kernel32Extra.COMPRESSION_FORMAT_NONE
                )).getPointer(),
                2,
                null, 0,
                new IntByReference(),
                null
            )) throw new IOException("Unable to alter compression attribute of " + file);
        } finally {
            Kernel32.INSTANCE.CloseHandle(hFile);
        }
    }


    public static boolean volumeSupportsFileCompression(File file) throws IOException {
        IntByReference flags = new IntByReference();
        if (!Kernel32Extra.INSTANCE.GetVolumeInformation(
            pathString(file.getAbsoluteFile().toPath().getRoot().toFile()),
            null, 0,
            null,
            null,
            flags,
            null, 0
        )) throw new IOException("GetVolumeInformation failure");
        return (flags.getValue() & Kernel32.FILE_FILE_COMPRESSION) != 0;
    }
}

isOther():错。isRegularFile():true;与其他文件相同。不走运。我检查了WindowsFileSystem类并发现:私有静态最终集supportedFileAttributeViews=Collections.unmodifiableSet(新哈希集(Arrays.asList(“basic”、“dos”、“acl”、“owner”、“user”));这意味着WindowsFileSystem只公开标准属性视图。我想说:把它添加到答案中。我认为如果你把这段代码贡献给jna,那就太好了。你可以随时与他们联系