我在Java中将3D字节矩阵(作为无符号字节)写入文本文件时遇到问题。
矩阵是3D,看起来像wMatrix3D[k][j][i]
。我想将它用于文本文件,因此值由空格分隔,并且每1,000个值都有一个换行符(每行有1,000个像素值,1,000行表示图像的1,000 x 1,000文本文件)。
目前,我这样做:
BufferedWriter out = new BufferedWriter(new FileWriter(imgout));
//Parse Headers
for(int countHeaderLines = 0; countHeaderLines < numHeaders; countHeaderLines+=1){
out.write(headers[countHeaderLines] + "\n");
}
System.out.println("Wrote Headers");
//Parse 1,000,000 x 1,000 2D matrix into 3D (1,000 x 1,000) x 1,000 matrix
System.out.println("Writing main matrix to text...");
//String slice = new String();
for(int k = 0; k < numLayers; k++){
for(int j = 0; j < numRows; j++){
String rowStr = new String();
for(int i = 0; i < numColumns; i++){
rowStr += Integer.toString((Integer.valueOf(wMatrix3D[k][j][i]) & 0xFF)) + " ";
}
out.write(rowStr + "\n");
}
/*if( (k+1) % 5 == 0){
slice = new String();
out.write(slice);
System.out.println("Writing Set of 10:" + k);
}*/
System.out.println("k: " + k);
}
但是,这种方式非常慢。有没有更有效的方法来做到这一点?在C中我使用“fprintf”没有问题,但在Java中,我无法让它运行良好。
答案 0 :(得分:0)
你正在一个文件上写10亿个整数,所以假设每个数字至少有1个字节+每个空格1个字节,忽略换行符,你已经是必须写在磁盘上的2千兆字节数据。
现在这是一个很好的数量肯定需要时间,但您可以考虑在BufferedWriter
周围使用PrintWriter
,这样您就可以直接使用其他许多可以更优化的操作,例如
void print(int i)
此外,您的矩阵似乎存储为字符串(因为您使用Integer.valueOf(...)
)将字符串转换为整数,然后您和它们再次转换回来。我想你可以节省一些时间已经把所有内容都作为int (或者无论如何这似乎更有意义)。
还要考虑使用StringBuilder
而不是像你一样在长字符串上连接。但我认为你不应该连接任何东西(使用PrintWriter
并优化数据结构)。
如果您的数据不是人类可读的,那么只需跳过字符串并保存二进制数据,您将获得至少10倍的速度。
答案 1 :(得分:0)
你必须记住,你有效地执行了10亿次中央循环。没有什么可以做的,以减少它,因为这是3d数组中的值的数量。你所希望做的就是让循环尽可能紧。
通过'添加'(使用+运算符)创建字符串效率非常低。减少您创建的字符串数量(每次使用+运算符连接它们时都会发生这种情况)会有所帮助。请考虑使用StringBuilder。
StringBuilder rowStr = new StringBuilder();
...
rowStr.append(...);
...
rowStr.append("\n");
out.write(rowStr.toString());
另外,不要对Integer.valueOf的结果使用Integer.toString。尝试转换为int并处理结果为负的情况。
任何时候你都可以在内循环中删除新对象的构造,你将节省时间。
答案 2 :(得分:0)
Array
和byte
都是Serializable
。只需通过ObjectOutputStream
将数组写入文件。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
class MatrixWriter {
public static void main(String... a) throws FileNotFoundException,
IOException, ClassNotFoundException {
byte[][][] data = new byte[][][] {
{ { 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 } },
{ { 9, 10 }, { 11, 12 } } };
String filename = "data.ser";
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
filename));
out.writeObject(data);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
filename));
byte[][][] array = (byte[][][]) in.readObject();
in.close();
for (byte[][] b : array) {
System.out.print("[");
for (byte[] c : b) {
System.out.print(Arrays.toString(c));
}
System.out.println("]");
}
}
}
答案 3 :(得分:0)
您在其他答案中获得的大部分输入都是正确的。但找出导致性能问题的最佳方法是分析您的应用程序。 Netbeans IDE实际上内置了一个不错的分析器。如果您要分析您的应用程序,最好使用矩阵的子集(我尝试了200 ^ 3次迭代),您会注意到字符串操作是您的问题。
每次连接字符串时,您都在后台创建String
对象。正如其他答案让你意识到的那样,你做了十亿次。因此,迈向良好解决方案的第一步是在每次迭代时停止创建对象。这可以通过使用StringBuilder
使用append()
来连接值和setLength(0)
来重用字符数组来完成。这将产生轻微的改进,因为每次迭代只创建一个字符串。另一种方法是使用您想要编写的每个字符串调用out.write()
,而不必将它们连接起来。您可以在下面看到结果:
使用StringBuilder:
直接发送到BufferedWriter:
仅供参考,我读过Memory Mapped Files提高文件写入速度。我见过的唯一缺点是你必须事先知道预期的文件大小。