0

テキスト ファイルに 3D バイト マトリックス (符号なしバイトとして) を書き込む Java に問題があります。マトリックスは 3D で、 のように見えwMatrix3D[k][j][i]ます。値が空白で区切られ、値が 1,000 個ごとに改行されるように、テキスト ファイルに保存します (1 行あたり 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);
}

ただし、この方法は非常に遅いです。これを行うためのより効率的な方法はありますか?CIでは「fprintf」を使用しても問題ありませんが、Javaではうまく機能しません。

4

4 に答える 4

0

ArraysとbytesはどちらもSerializableJavaです。を介して配列をファイルに書き込むだけ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("]");
        }
    }
}
于 2012-06-20T04:47:32.863 に答える
0

他の回答で得ている入力のほとんどは正しいです。しかし、パフォーマンスの問題の原因を突き止める最良の方法は、アプリケーションをプロファイリングすることです。実際、Netbeans IDE には適切なプロファイラーが組み込まれています。できればマトリックスのサブセットを使用してアプリケーションをプロファイリングする場合 (200^3 回の反復を試みました)、文字列操作が問題であることがわかります。

ここに画像の説明を入力

文字列を連結するたびStringに、バックグラウンドでオブジェクトを作成しています。他の答えがあなたに気づかせたように、あなたはそれを何十億回もやっています。したがって、適切な解決策に向けた最初のステップは、反復ごとにオブジェクトの作成を停止することです。これは、StringBuilderを使用append()して値を連結setLength(0)し、文字配列を再利用することで実行できます。各反復で 1 つの文字列のみが作成されるため、これによりわずかな改善が得られます。もう 1 つの方法は、out.write()書きたい各文字列を連結せずに使用して呼び出すことです。以下の結果を確認できます。

StringBuilder の使用:

ここに画像の説明を入力

BufferedWriter に直接送信します。

ここに画像の説明を入力

参考までに、 Memory Mapped Filesを使用するとファイルの書き込み速度が向上することを読みました。私が見た唯一の欠点は、予想されるファイルサイズを事前に知っておく必要があることです。

于 2012-06-20T07:13:41.223 に答える
0

ファイルに 10 億個の整数を書き込んでいるので、数値ごとに最低 1 バイト + 空白ごとに 1 バイトと仮定すると、改行を無視すると、すでに 2 ギガバイトのデータをディスクに書き込む必要があります。

これは確かに時間がかかるかなりの量ですが、より最適化できる他の多くの操作を直接使用できるように、PrintWriter周りの使用を検討できます。BufferedWriter

void print(int i) 

さらに、行列は文字列として格納されているようです (を使用しているためInteger.valueOf(...)) 文字列を整数に変換し、それらを AND して再度変換します。すでにすべてを int にすることで、時間を節約できると思います(いずれにせよ、これはより理にかなっているように思えます)。

StringBuilderあなたがやっているように、長い文字列を連結する代わりにa を使用することも検討してください。PrintWriterしかし、(データ構造を使用して最適化することにより)何も連結する必要はないと思います。

データが人間に読み取られることを意図していない場合は、文字列をスキップしてバイナリ データを保存するだけで、少なくとも 10 倍の速度が得られます。

于 2012-06-20T04:36:01.720 に答える
0

中央ループを効果的に 10 億回実行していることを覚えておく必要があります。それは 3 次元配列内の値の数であるため、それを減らすためにできることは何もありません。あなたが望むことができるのは、そのループをできるだけタイトにすることだけです.

「追加」(+ 演算子を使用) による文字列の作成は非常に非効率的です。作成する文字列の数を減らす (+ 演算子を使用して連結するたびに発生します) と役立ちます。代わりに StringBuilder の使用を検討してください。

StringBuilder rowStr = new StringBuilder();
    ...
    rowStr.append(...);
    ...
rowStr.append("\n");
out.write(rowStr.toString());

また、Integer.valueOf の結果に対して Integer.toString を使用しないでください。int にキャストして、結果が負の場合を処理してみてください。

内側のループで新しいオブジェクトの構築を削除できるときはいつでも、時間を節約できます。

于 2012-06-20T04:45:13.993 に答える