在 Java 中获取系统块大小

Posted

技术标签:

【中文标题】在 Java 中获取系统块大小【英文标题】:Get system block size in Java 【发布时间】:2012-05-16 01:56:34 【问题描述】:

我正在尝试编写最快、最优化的文件保存方法。有没有办法在java中获取系统块大小? System.getProperty("block.size") 之类的东西。

【问题讨论】:

这里没有系统属性,也无法通过纯java获取信息。如果这是一个问题,您应该使用 BufferedWriter 或 BufferedOutputStream +1;好问题。但是 IMO 从系统环境中获取存储块大小没有意义,因为您可能在由不同类型的存储支持的给定系统上有多个挂载点。 这就是他们构建操作系统的原因——让您免于这些细节 仅供参考:***.com/questions/3892186/… @ControlAltDel 我猜这个抽象是泄漏的,因为即使你使用 BufferedWriter,你仍然必须选择一个缓冲区大小,然后又回到了如何获取块大小的相同问题那个文件。 【参考方案1】:

“可能的最快最佳方式”肯定是使用您能负担得起的最大缓冲区进行写入;确保它的大小是 2 的幂(想到兆字节);并确保写入本身是缓冲区对齐的:

new BufferedOutputStream(new FileOutputStream(file), 1024*1024);

只要您超过系统块大小(您将处于此大小)并保持与它对齐(@9​​87654322@ 保证),这几乎是最佳状态。

您还应该查看FileChannel.transferTo(),注意您必须在循环中调用它,并且到目前为止的实际实现似乎没有使用任何低级操作系统原语(与广告相反),只是您可以自己编写同样的循环。

【讨论】:

我在手机 (Nexus 5X) 上为我的 android 应用程序做了一些基准测试:小文件 (3,5Mb) 和大文件 (175 Mb)。并发现黄金大小将是 524288 长度的 byte[]。好吧,如果您根据文件大小在小缓冲区 4Kb 和大缓冲区 524Kb 之间切换,您可能会赢得 10-20 毫秒,但这不值得。坚持使用 524 Kb。【参考方案2】:

我认为没有 java 函数可以做到这一点。但是,有一种依赖于系统的方法来检索该信息。看看这个answer。您需要使用 Runtime.exec() 并解析数据。

【讨论】:

感谢您的链接。看来这是一个很好的解决方案。【参考方案3】:

没有 System 属性,但您可以使用 Java 使用的任何内容来满足自己的需要,并放心,这是最适合您的 OS/Java 版本组合的。

此解决方案利用了以下事实:Java 的 BufferedXXXStream 类中用于保存数据的 bufprotected 变量而不是 private 变量:

class IdealBlockSize 
    // You could alternatively use BufferedInputStream and System.in .
    private static class MyBufferedOS extends BufferedOutputStream 
        public MyBufferedOS()  super(System.out); 
        public MyBufferedOS(OutputStream out)  super(out); 
        public int bufferSize()  return buf.length; 
    

    public static int VALUE = new IdealBlockSize.MyBufferedOS().bufferSize();

然后,您可以在应用程序启动代码中调用它们,如下所示:

System.out.printf("Ideal block size: %d\n", IdealBlockSize.VALUE);

// Output
// Ideal block size: 8192

此解决方案允许您拥有刚刚大到足以达到最佳状态的缓冲区。

【讨论】:

您会得到 8192,因为该默认值是硬编码在 BufferedOutputStream 构造函数中的。不进行检测。我相信 OP 正在寻找一种基于底层块设备优化缓冲区大小的解决方案。如果他的块设备(通常)是 4k 对齐的,那么这肯定不是最佳的。 选择 8192 可能是对正交要求或读取与写入、顺序与随机访问以及不同操作系统选择的折衷。 OP 想写得快。根据原因,直接 IO 甚至可能是最好的,如果使用同步,那么 FS 的逻辑块大小可能是最佳的。大多数人设置缓冲区大小的经验来自复制,其中大部分时钟时间实际上用于读取。在这种情况下,由于操作系统预读缓冲区,更大的缓冲区会有所帮助。这不是只写的情况。【参考方案4】:

从 Java 9 开始,您可以使用 FileSystem 和 FileStore 类根据您的本机操作系统实现的文件系统获取系统磁盘块大小。代码如下:

    FileSystem fs = FileSystems.getDefault();
    Iterable<Path> roots = fs.getRootDirectories();
    for (FileStore store: fs.getFileStores()) 
        Iterator<Path> i = roots.iterator();
        while(i.hasNext()) 
            if(store.name().startsWith(i.next().toString())) 
                System.out.println("Name: " + store.name() + ", Read only: " + store.isReadOnly() + ", Type: " + store.type() + ", Block: " + store.getBlockSize() + " Bytes");
            
        
    

【讨论】:

您的代码在 Linux 上会产生错误,因为始终至少有一个根 the 根 (/) 启动所有路径。最好使用 Files.getFileStore(path) 检索适当的 FileStore,它会为您进行正确的计算。

以上是关于在 Java 中获取系统块大小的主要内容,如果未能解决你的问题,请参考以下文章

java如何获取一个对象的大小

从java获取操作系统内存大小

获取 API 等待已定义块大小的块

Visual Studio 2010 C++:获取 malloc 分配的内存块大小

Java获取MAXIMIZED状态窗口大小

CUDA如何获取网格、块、线程大小和并行化非方阵计算