Java中将小文件连续读取到对象中的最有效方法

时间:2019-05-18 16:54:04

标签: java performance kotlin nio

tl / dr:我需要使我的应用程序中的某些值保持最新,并带有〜10个小文件中的值,但我担心一遍又一遍地读取该值会产生大量的GC开销。是否创建一堆无缓冲的文件读取器并对其进行轮询,或者有什么方法可以将文件中的值“映射”到java Double中,以便稍后(可能)值发生更改时可以重新运行? >

长版:我有一些物理传感器(陀螺仪,转速计),它们ev3dev可以将它们的当前值作为虚拟文件系统中的小文件公开显示。就像一个名为“ / sys / bus / lego / drivers / ev3-analog-sensor / angle”的文件,其中包含56.26712

或者在下一刻它包含58.9834

我希望我的应用程序中的一个值尽可能与该文件保持同步。我可以让您的标准循环包含MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());(来自here),但是如果将它放入快速循环中,这似乎分配很多开销。

也许使用扫描仪,或者 FileChannel inChannel = aFile.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); while(inChannel.read(buffer) > 0)...

我还没有发现KeepInSyncWithFile(myFloatArray, File("./angle", MODE.FILE_TO_VALUE, 10, TimeUnits.MS)的神奇功能

Java 8 +

2 个答案:

答案 0 :(得分:2)

请问您正在谈论/sys虚拟文件系统上的伪文件,标准WatchService不太可能适用于它们。为了获取更新的值,您需要阅读这些文件。

好消息是,您可以以无垃圾的方式继续阅读,即完全无需分配。打开文件并仅分配一次缓冲区,每当您要读取一个值时,请寻找文件的开头并读取到现有的预分配缓冲区。

代码如下:

public class DeviceReader implements Closeable {
    private final RandomAccessFile file;
    private final byte[] buf = new byte[512];

    public DeviceReader(String fileName) throws IOException {
        this.file = new RandomAccessFile(fileName, "r");
    }

    @Override
    public void close() throws IOException {
        file.close();
    }

    public synchronized double readDouble() throws IOException {
        file.seek(0);
        int length = file.read(buf);
        if (length <= 0) {
            throw new EOFException();
        }

        int sign = 1;
        long exp = 0;
        long value = 0;

        for (int i = 0; i < length; i++) {
            byte ch = buf[i];
            if (ch == '-') {
                sign = -1;
            } else if (ch == '.') {
                exp = 1;
            } else if (ch >= '0' && ch <= '9') {
                value = (value * 10) + (ch - '0');
                exp *= 10;
            } else if (ch < ' ') {
                break;
            }
        }

        return (double) (sign * value) / Math.max(1, exp);
    }
}

请注意,我是从byte[]缓冲区中手动解析浮点数的。调用Double.parseDouble会容易得多,但是在这种情况下,您必须将byte[]转换为String,并且该算法将不再免费分配。

答案 1 :(得分:-1)

我不能为此提供担保,但是File Observer可能值得研究。您可以在应用程序中缓存最新值,并通过FileObserver观察文件,以查看是否发生任何修改事件。我个人没有使用它的经验,所以我不能肯定地说它是否可以与系统文件一起使用。但是,如果这样做的话,与仅在循环中重复查找文件相比,这是一个更好的解决方案。