低效输出流¶
ID: java/inefficient-output-stream
Kind: problem
Security severity:
Severity: warning
Precision: very-high
Tags:
- efficiency
Query suites:
- java-security-and-quality.qls
类 java.io.OutputStream
和 java.io.FilterOutputStream
只要求子类实现方法 write(byte b)
。通常,OutputStream
的使用不会写入单个字节,而是通过 write(byte[] b, int off, int len)
方法写入数组。此方法的默认实现(不需要覆盖)为数组中的每个字节调用 write(byte b)
。如果此方法涉及 I/O,例如访问网络或磁盘,则可能会产生大量开销。
建议¶
始终提供 write(byte[] b, int off, int len)
方法的实现。
示例¶
以下示例显示 OutputStream
的子类,它仅封装 DigestOutputStream
以确认它写入文件的数据具有预期的 MD5 哈希。如果没有 write(byte[] b, int off, int len)
的实现,这将非常慢,因为它会对每个写入的字节调用 DigestOutputStream.write(byte b)
和 FileOutputStream.write(byte b)
。
public class DigestCheckingFileOutputStream extends OutputStream {
private DigestOutputStream digest;
private byte[] expectedMD5;
public DigestCheckingFileOutputStream(File file, byte[] expectedMD5)
throws IOException, NoSuchAlgorithmException {
this.expectedMD5 = expectedMD5;
digest = new DigestOutputStream(new FileOutputStream(file),
MessageDigest.getInstance("MD5"));
}
@Override
public void write(int b) throws IOException {
digest.write(b);
}
@Override
public void close() throws IOException {
super.close();
digest.close();
byte[] md5 = digest.getMessageDigest().digest();
if (expectedMD5 != null && !Arrays.equals(expectedMD5, md5)) {
throw new InternalError();
}
}
}
可以更新示例以使用更有效的方法。在这种情况下,对 write(byte[] b, int off, int len)
的调用仅转发到 DigestOutputStream.write(byte[] b, int off, int len)
。
public class DigestCheckingFileOutputStream extends OutputStream {
private DigestOutputStream digest;
private byte[] expectedMD5;
public DigestCheckingFileOutputStream(File file, byte[] expectedMD5)
throws IOException, NoSuchAlgorithmException {
this.expectedMD5 = expectedMD5;
digest = new DigestOutputStream(new FileOutputStream(file),
MessageDigest.getInstance("MD5"));
}
@Override
public void write(int b) throws IOException {
digest.write(b);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
digest.write(b, off, len);
}
@Override
public void close() throws IOException {
super.close();
digest.close();
byte[] md5 = digest.getMessageDigest().digest();
if (expectedMD5 != null && !Arrays.equals(expectedMD5, md5)) {
throw new InternalError();
}
}
}