Самый эффективный способ в Java постоянно читать небольшие файлы в объект - PullRequest
2 голосов
/ 18 мая 2019

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()); (из здесь ), но это выглядит как чрезмерное распределение ресурсов, если поместить его в быстрый цикл.

Может быть, что-то со сканером, или 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 ]

2 голосов
/ 19 мая 2019

Пока вы говорите о псевдофайлах в виртуальной файловой системе /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, и алгоритм больше не будет выделяться бесплатно.

0 голосов
/ 18 мая 2019

Я не могу ручаться за это, но File Observer может стоить изучить.Вы можете кэшировать последние значения в вашем приложении и наблюдать файл через FileObserver, чтобы найти, происходит ли какое-либо событие модификации.У меня лично нет опыта работы с ним, поэтому я не могу точно сказать, будет ли он работать с системными файлами.Но если это так, то это лучшее решение по сравнению с простым повторным поиском файла в цикле.

...