在 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);
只要您超过系统块大小(您将处于此大小)并保持与它对齐(@987654322@ 保证),这几乎是最佳状态。
您还应该查看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
类中用于保存数据的 buf
是 protected
变量而不是 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 中获取系统块大小的主要内容,如果未能解决你的问题,请参考以下文章