Записать массив float в файл на Java - PullRequest
4 голосов
/ 13 сентября 2011

Я читаю в файле NetCDF и хочу прочитать каждый массив как массив с плавающей точкой, а затем записать массив с плавающей точкой в ​​новый файл. Я могу заставить его работать, если я читаю в массиве с плавающей точкой, а затем перебираю каждый элемент массива (используя DataOutputStream), но это очень и очень медленно, мои файлы NetCDF имеют размер более 1 ГБ.

Я пытался использовать ObjectOutputStream, но это записывает дополнительные байты информации.

Итак, подведем итоги. 1. Откройте файл NetCDF 2. Считать массив с плавающей запятой x из файла NetCDF 3. Записать массив с плавающей запятой x в файл необработанных данных за один шаг 4. Повторите шаг 2 с x + 1

Ответы [ 5 ]

3 голосов
/ 13 сентября 2011

Хорошо, у вас есть 1 ГБ для чтения и 1 ГБ для записи. В зависимости от вашего жесткого диска вы можете получить скорость чтения около 100 МБ / с и скорость записи 60 МБ / с. Это означает, что чтение и запись займет около 27 секунд.

Какова скорость вашего привода и насколько медленнее вы это видите?

Если вы хотите проверить скорость вашего диска без какой-либо обработки, то сколько времени занимает копирование файла, к которому вы недавно не обращались (т.е. он не находится в кеше диска). Это даст вам представление о минимальная задержка, которую вы можете ожидать, чтобы прочитать, а затем записать большую часть данных из файла (т.е. без обработки или участия Java)


Для тех, кто хочет знать, как сделать копию данных без цикла, т. Е. Он не просто вызывает метод, который зацикливается на вас.

FloatBuffer src = // readable memory mapped file.
FloatByffer dest = // writeable memory mapped file.
src.position(start);
src.limit(end);
dest.put(src);

Если у вас смешанные типы данных, вы можете использовать ByteBuffer, который условно копирует байт за раз, но в действительности может использовать длинный или более широкий тип для копирования 8 или более байт за раз. то есть все, что может делать процессор.

Для небольших блоков это будет использовать цикл, но для больших блоков он может использовать трюки с отображением страниц в ОС. В любом случае, как это происходит, не определено в Java, но, скорее всего, это самый быстрый способ копирования данных.

Большинство этих трюков имеют значение только в том случае, если вы копируете файл, уже находящийся в памяти, в кэшированный файл. Как только вы читаете файл с диска или файл слишком велик для кеширования, пропускная способность ввода-вывода вашего физического диска - единственное, что действительно имеет значение.

Это связано с тем, что процессор может копировать данные со скоростью 6 ГБ / с в основную память, но только 60-100 МБ / с на жесткий диск. Если копия в ЦП / памяти в 2, 10 или 50 раз медленнее, чем могла бы быть, она все равно будет ждать диска. Примечание: без буферизации это вполне возможно и хуже, но при условии, что у вас есть простая буферизация, процессор будет быстрее диска.

1 голос
/ 29 октября 2012

Я столкнулся с той же проблемой и оставлю здесь свое решение только для дальнейшего использования.

Очень медленно перебирать массив с плавающей точкой и вызывать DataOutputStream.writeFloat для каждого из них. Вместо этого, преобразуйте float в байтовый массив и запишите этот массив сразу:

Slow:

DataOutputStream out = ...;
for (int i=0; i<floatarray.length; ++i)
    out.writeFloat(floatarray[i]);

намного быстрее

DataOutputStream out = ...;
byte buf[] = new byte[4*floatarray.length];
for (int i=0; i<floatarray.length; ++i)
{
    int val = Float.floatToRawIntBits(probs[i]);
    buf[4 * i] = (byte) (val >> 24);
    buf[4 * i + 1] = (byte) (val >> 16) ;
    buf[4 * i + 2] = (byte) (val >> 8);
    buf[4 * i + 3] = (byte) (val);
}

out.write(buf);

Если ваш массив очень большой (> 100 КБ), разбейте его на куски, чтобы избежать переполнения кучи буферным массивом.

1 голос
/ 02 декабря 2011

1) при написании используйте BufferedOutputStream, вы получите ускорение в 100 раз.

2) при чтении читайте не менее 10 КБ на чтение, возможно, лучше 100 КБ.

3) опубликуйте свой код.

0 голосов
/ 23 октября 2011

Боковой раствор:

Если это одноразовое поколение (или если вы хотите автоматизировать его с помощью сценария Ant), и у вас есть доступ к какой-либо среде Unix, вы можете использовать NCDUMP вместо этого на Яве. Что-то вроде:

ncdump -v your_variable your_file.nc | [awk] > float_array.txt

При желании вы можете контролировать точность чисел с параметром -p. Я просто запустил его на 3GB-файле NetCDF, и он работал нормально. Как бы я ни любил Java, это, наверное, самый быстрый способ сделать то, что вы хотите.

0 голосов
/ 21 октября 2011

Если вы используете библиотеку Unidata NetCDF , возможно, ваша проблема не в написании, а в механизме кэширования библиотек NetCDF.

     NetcdfFile file = NetcdfFile.open(filename);
     Variable variable = openFile.findVariable(variable name);
     for (...) {
          read data
          variable.invalidateCache();
      }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...