关于文件:是否有Java相当于GetCompressedFileSize的文件?

 2020-06-30 

Is there a Java equivalent of GetCompressedFileSize?

我希望获得Java中稀疏文件的准确(即磁盘上的实际大小,而不是包括所有0的正常大小)的度量。

在Windows上的C ++中,将使用GetCompressedFileSize。 我还没有想过如何用Java做到这一点?

如果没有直接的等效项,我将如何测量稀疏文件中的数据,而不是包括所有零的大小?

为了澄清起见,我希望它能在Linux OS和Windows上都运行备用文件测量,但是我不介意编写两个单独的应用程序!


如果您需要纯Java解决方案,则可以尝试jnr-posix。这是一个示例实现

1
2
3
4
5
6
import jnr.posix.*;

final POSIX p = POSIXFactory.getPOSIX();
final int S_BLKSIZE = 512; // from sys/stat.h
final FileStat stat = p.stat("/path/to/file");
final long bytes = stat.blocks() * S_BLKSIZE;

但是当前该功能不适用于Windows。在解决该问题之前,您必须使用类似于以下平台的代码

  • 在Linux上,使用stat64系统调用

    The st_blocks field indicates the number of blocks allocated to the file, 512-byte units. (This may be smaller than st_size/512 when the file has holes.)

    • 您也可以运行stat命令。分配的块数可以在Blocks字段中看到,或使用%b格式说明符打印
    • 或使用du命令(不带--apparent-size选项)

      --apparent-size

      • print apparent sizes, rather than disk usage; although the apparent size is usually smaller, it may be larger due to holes in ('sparse') files, internal fragmentation, indirect blocks, and the like
  • 在Windows上,您可以调用GetCompressedFileSize API

    • 或者,您也可以使用管理员权限运行fsutil file layout以获取有关文件的详细信息。找到$DATA流。

      • 如果看到居民|像这样的标志中没有分配群集,则它是一个驻留文件,磁盘上的大小将为0。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        PS C:\\Users>  fsutil file layout .\\desktop.ini

        ********* File 0x000800000003dbde *********
        File reference number   : 0x000800000003dbde
        File attributes         : 0x00000026: Hidden | System | Archive
        File entry flags        : 0x00000000
        Link (ParentID: Name)   : 0x001f0000000238c8: HLINK Name   : \\Users\\desktop.ini
        ...
        Stream                  : 0x080  ::$DATA
            Attributes          : 0x00000000: *NONE*
            Flags               : 0x0000000c: Resident | No clusters allocated
            Size                : 174
            Allocated Size      : 176
      • 如果您没有看到常驻标志,请检查分配的大小字段,它是磁盘上文件的大小

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        PS D:\\>  fsutil file layout .\
        onresident.txt

        ********* File 0x000400000000084e *********
        File reference number   : 0x000400000000084e
        File attributes         : 0x00000020: Archive
        File entry flags        : 0x00000000
        Link (ParentID: Name)   : 0x0005000000000005: HLINK Name   : \
        onresident.txt
        ...
        Stream                  : 0x080  ::$DATA
            Attributes          : 0x00000000: *NONE*
            Flags               : 0x00000000: *NONE*
            Size                : 1,520
            Allocated Size      : 4,096
            Extents             : 1 Extents
                                : 1: VCN: 0 Clusters: 1 LCN: 1,497,204

有关更多信息,您可以阅读以下问题

  • 如何查询"磁盘大小"文件信息?
  • 获取磁盘上文件的大小

如果仅在Windows上执行此操作,则可以使用Java Native Interface编写它

1
2
3
class NativeInterface{
   public static native long GetCompressedFileSize(String filename);
}

并在C / C ++文件中:

1
2
3
4
5
6
7
8
9
10
11
extern"C"
JNIEXPORT jlong JNICALL Java_NativeInterface_GetCompressedFileSize
  (JNIEnv *env, jobject obj, jstring javaString)
{
    const char *nativeString = env->GetStringUTFChars(javaString, 0);

    char buffer[512];
    strcpy(buffer, nativeString);
    env->ReleaseStringUTFChars(javaString, nativeString);
    return (jlong) GetCompressedFileSize(buffer, NULL);
}

由于给出了针对Windows的答案。我将尝试提供Linux。

我不确定,但是我认为它将成功(C ++):

1
2
#include <linux/fs.h>
ioctl(file, BLKGETSIZE64, &file_size_in_bytes);

可以用@Aniket答案(JNI)中描述的相同方式加载