6

配列バイトに変換されたファイルを受け入れて暗号化する暗号化アルゴリズム(AES)があります。非常に大きなファイルを処理するため、JVMのメモリが不足する可能性があります。それぞれがファイルの一部を含む複数のバイト配列でファイルを読み取ることを計画しています。次に、アルゴリズムを繰り返しフィードします。最後に、それらをマージして暗号化されたファイルを作成します。

だから私の質問は:ファイルを部分的に複数のバイト配列に読み取る方法はありますか?

次を使用してファイルをバイト配列に読み取ることができると思いました。

    IOUtils.toByteArray(InputStream input).

次に、以下を使用して配列を複数のバイトに分割します。

    Arrays.copyOfRange()

しかし、ファイルを読み取るコードByteArrayによって、JVMのメモリが不足するのではないかと心配しています。

4

2 に答える 2

5

Javaで暗号ストリームを検索します。それらを使用してストリームをその場で暗号化/復号化できるため、すべてをメモリに保存する必要はありません。あなたがしなければならないのはFileInputStream、あなたのソースファイルのレギュラーを暗号化されたシンクファイルのCipherOutputStreamあなたをラップしているものにコピーすることです。このコピーを作成するためのメソッドも便利に含まれています。FileOutputStreamIOUtilscopy(InputStream, OutputStream)

例えば:

public static void main(String[] args) {
    encryptFile("exampleInput.txt", "exampleOutput.txt");
}

public static void encryptFile(String source, String sink) {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream(source);
        CipherOutputStream cos = null;
        try {
            cos = new CipherOutputStream(new FileOutputStream(sink), getEncryptionCipher());
            IOUtils.copy(fis, cos);
        } finally {
            if (cos != null)
                cos.close();
        }
    } finally {
        if (fis != null)
            fis.close();
    }
}

private static Cipher getEncryptionCipher() {
    // Create AES cipher with whatever padding and other properties you want
    Cipher cipher = ... ;
    // Create AES secret key
    Key key = ... ;
    cipher.init(Cipher.ENCRYPT_MODE, key);
}

コピーされたバイト数を知る必要がある場合は、ファイルサイズがバイト(2 GB)を超えるかどうかのIOUtils.copyLarge代わりに使用できます。IOUtils.copyInteger.MAX_VALUE

ファイルを復号化するには、同じことを行いますが、のCipherInputStream 代わりにを使用し、 usingCipherOutputStreamを初期化します。CipherCipher.DECRYPT_MODE

Javaの暗号化ストリームの詳細については、こちらをご覧ください。

byteこれにより、独自の配列を格納する必要がなくなるため、スペースを節約できます。このシステムに保存さbyte[]れるのは、の内部のみです。これbyte[]は、十分な入力が入力され、暗号化されたブロックがによって返されるたびに、またはが閉じられるとオンにCipherなるたびにクリアされます。ただし、これはすべて内部であり、すべてが管理されているため、これについて心配する必要はありません。Cipher.updateCipher.doFinalCipherOutputStream

編集:これにより、特定の暗号化例外が無視される可能性があることに注意してください。特にBadPaddingExceptionIllegalBlockSizeException。この動作は、CipherOutputStreamソースコードに記載されています。(確かに、このソースはOpenJDKからのものですが、おそらくSun JDKでも同じことを行います。)また、CipherOutputStream javadocsから:

java.io.OutputStreamこのクラスは、その祖先クラスとのセマンティクス、特に失敗セマンティクスに厳密に準拠していjava.io.FilterOutputStreamます。このクラスには、その祖先クラスで指定されたメソッドが正確にあり、それらすべてをオーバーライドします。さらに、このクラスは、その祖先クラスによってスローされないすべての例外をキャッチします。

ここでの太線は、暗号化例外が無視されることを意味します。これにより、特にAESのようなブロックおよび/またはパディング暗号化アルゴリズムの場合、暗号化されたファイルを読み取ろうとしているときに予期しない動作が発生する可能性があります。CipherInputStream暗号化された(または復号化された)ファイルの出力がゼロまたは部分的になることに注意してください。

于 2012-11-07T17:32:42.707 に答える
1

を使用している場合は、 IOUtils.copyLarge()IOUtilsを検討する必要があります。

public static long copyLarge(InputStream input,
                             OutputStream output,
                             long inputOffset,
                             long length)

ByteArrayOutputStreamを出力として指定します。次に、offset / lengthを使用して、ファイルのセクションを反復処理およびロードできます。

ドキュメントから:

一部またはすべてのバイトを大きな(2GBを超える)InputStreamからOutputStreamにコピーし、オプションで入力バイトをスキップします。

于 2012-11-07T16:58:58.097 に答える