草庐IT

Java NTFS 压缩属性

coder 2024-03-29 原文

我需要从 Java 读取和修改 NTFS 分区上文件的“压缩”属性。我在 java.nio.file.attribute 中想象了一些东西package 可以做到——见鬼,它是一个足够复杂的包,但我找不到这个属性。

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

我试过了 Files.readAttributes它允许从特定的“属性 View ”动态检索所有属性。在“dos:*”下,只有 DosFileAttributes 类的公共(public)方法已经可用的相同属性。我尝试了“ntfs:*”和“windows:*”,但它们没有被接受为有效的 View 名称。

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

我想知道是否要支付给 attrib命令(接受它不适用于安装在 Linux 或其他操作系统下的 NTFS 分区的限制)但它似乎也不支持该属性。帮忙?

最佳答案

由于标准 Java API 似乎确实缺少此功能,因此我查看了自己使用 JNA 进行的操作.这是我第一次使用 JNA。它没有我想要的那么漂亮,而且 JNA 的代码似乎非常缺乏泛型,但它比使用 JNI 并尝试为所需的不同平台(最低 x86 和 x64)设置糟糕的交叉编译器要好一百倍即使您只针对一个操作系统)。最初是烦人的编译过程驱使我从 C++ 转向 Java,我希望永远不必回到它。

无论如何,这似乎可行。希望它对其他人也有用。它提供了四种公共(public)方法:

  • isAvailable() -- 调用其他方法是否有效(即,我们在 Windows 上并且 JNA native 库加载正常)
  • isCompressed(文件)
  • setCompressed(文件, boolean 值)
  • volumeSupportsFileCompression(File) -- 询问 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;
    }
}

关于Java NTFS 压缩属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19401889/

有关Java NTFS 压缩属性的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  5. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  6. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  7. ruby - Chef Ruby 遍历 .erb 模板文件中的属性 - 2

    所以这可能有点令人困惑,但请耐心等待。简而言之,我想遍历具有特定键值的所有属性,然后如果值不为空,则将它们插入到模板中。这是我的代码:属性:#===DefaultfileConfigurations#default['elasticsearch']['default']['ES_USER']=''default['elasticsearch']['default']['ES_GROUP']=''default['elasticsearch']['default']['ES_HEAP_SIZE']=''default['elasticsearch']['default']['MAX_OP

  8. ruby - 获取数组中的值并最小化某个类属性的最优雅的方法是什么? - 2

    假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)

  9. ruby-on-rails - 为模型创建状态属性 - 2

    我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,

  10. ruby - Ruby 的压缩库? - 2

    是否有任何可用于Ruby的开源压缩/解压库?有没有人实现过LZW?或者,是否有任何使用压缩组件的开源库可以提取出来独立使用?编辑——感谢您的回答!我应该提到我必须压缩的是只驻留在数据库中的长字符串(我不会压缩文件)。此外,如果可以执行此操作的任何库都具有用于客户端压缩/分解的等效JavaScript实现,那将是理想的,因为这将用于Web应用程序。 最佳答案 您会在rubystdlib下找到所有已交付的ruby​​库的一个很好的列表.我会使用zlib库,它是开放的,无处不在,您会发现几乎所有语言的库!

随机推荐