CodeQL 文档

低效输出流

ID: java/inefficient-output-stream
Kind: problem
Security severity: 
Severity: warning
Precision: very-high
Tags:
   - efficiency
Query suites:
   - java-security-and-quality.qls

点击以在 CodeQL 存储库中查看查询

java.io.OutputStreamjava.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();
		}
	}
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私