用Java将浮点数组写入文件

用Java将浮点数组写入文件,java,arrays,floating-point,netcdf,Java,Arrays,Floating Point,Netcdf,我正在读取一个NetCDF文件,我想将每个数组作为浮点数组读取,然后将浮点数组写入一个新文件。如果我读入浮点数组,然后迭代数组中的每个元素(使用DataOutputStream),我可以让它工作,但是这非常非常慢,我的NetCDF文件超过1GB 我尝试使用ObjectOutputStream,但这会写入额外的信息字节 所以,概括一下。 1.打开NetCDF文件 2.从NetCDF文件读取浮点数组x 3.一步将浮点数组x写入原始数据文件 4.用x+1重复步骤2。好的,您有1 GB的读取空间和1 G

我正在读取一个NetCDF文件,我想将每个数组作为浮点数组读取,然后将浮点数组写入一个新文件。如果我读入浮点数组,然后迭代数组中的每个元素(使用DataOutputStream),我可以让它工作,但是这非常非常慢,我的NetCDF文件超过1GB

我尝试使用ObjectOutputStream,但这会写入额外的信息字节

所以,概括一下。 1.打开NetCDF文件 2.从NetCDF文件读取浮点数组x 3.一步将浮点数组x写入原始数据文件
4.用x+1重复步骤2。好的,您有1 GB的读取空间和1 GB的写入空间。根据您的硬盘驱动器,您可能会获得大约100 MB/s的读取速度和60 MB/s的写入速度。这意味着读写大约需要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个或更多字节。i、 无论CPU能做什么

对于小的块,这将使用循环,但是对于大的块,它可以在操作系统中使用页面映射技巧。无论如何,它是如何实现的并没有在Java中定义,但它可能是复制数据的最快方式

如果要将内存中已有的文件复制到缓存文件中,这些技巧中的大多数只会起作用。当您从磁盘读取文件或文件太大而无法缓存时,物理磁盘的IO带宽才是真正重要的

这是因为CPU可以以6 GB/s的速度将数据复制到主内存,但只能以60-100 MB/s的速度复制到硬盘。如果CPU/内存中的拷贝比可能的慢2倍、10倍或50倍,它仍将等待磁盘。注意:如果没有缓冲,这是完全可能的,而且更糟,但是如果您有任何简单的缓冲,CPU将比磁盘快。

如果您使用的是磁盘,您的问题可能不是写入,而是NetCDF库缓存机制

     NetcdfFile file = NetcdfFile.open(filename);
     Variable variable = openFile.findVariable(variable name);
     for (...) {
          read data
          variable.invalidateCache();
      }
横向解决方案:

如果这是一个一次性的生成(或者如果您愿意在Ant脚本中实现自动化),并且您可以访问某种Unix环境,那么您可以使用而不是使用Java。比如:

ncdump -v your_variable your_file.nc | [awk] > float_array.txt
如果需要,可以使用-p选项控制浮动的精度。我只是在一个3GB的NetCDF文件上运行了它,它运行得很好。尽管我非常喜欢Java,但这可能是实现您所需的最快方式。

1)在编写时,使用BufferedOutputStream,您将获得100倍的加速

2) 阅读时,每次阅读至少10K,可能100K更好


3) 发布您的代码。

我遇到了相同的问题,将在此处转储我的解决方案,仅供将来参考

迭代浮点数组并为每个浮点调用DataOutputStream.writeFloat非常缓慢。相反,将浮点值转换为字节数组,并一次性写入该数组:

慢:

DataOutputStream out=。。。;
对于(int i=0;i 24);
buf[4*i+1]=(字节)(val>>16);
buf[4*i+2]=(字节)(val>>8);
buf[4*i+3]=(字节)(val);
}
out.write(buf);

如果您的数组非常大(>100k),请将其分成若干块,以避免缓冲区数组的堆溢出。

我想您试图使用BufferedOutputStream来提高写入性能,对吗?我的计算机是全新的Mac Pro,速度非常快。是Java的开销太慢了。这是你已经测量过的东西,你可以看到差异,还是你只是“知道”,因为你从来没有错过换句话说,给我一些数字。我有两个高性能SSD驱动器,我可以用Java测量它们的性能,这不是瓶颈。
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);