【发布时间】:2021-07-31 00:56:36
【问题描述】:
在我的应用程序中,我需要遍历文件的内容以生成文件的固定大小块的哈希值。最终目标是实现 Amazon Glacier 的 Tree Hash 算法,我几乎一字不差地从他们的文档中复制了代码。
当我通过 SonarQube 运行以下代码时会出现问题:
byte[] buff = new byte[Mio];
int bytesRead;
while ((bytesRead = await inputStream.ReadAsync(buff, 0, Mio)) > 0) {
// Process the bytes read
}
我遇到了 while 循环的 Roslyn 问题。问题是“更改 'ReadAsync' 方法调用以使用 'Stream.ReadAsync(Memory, CancellationToken)' 重载”。根据描述,这是因为使用 Memory 类的方法比使用基本数组的方法效率更高。
当类可以从头到尾使用时,这可能是正确的。问题是,我需要将数据提供给HashAlgorithm 的ComputeHash 方法,并且它们没有任何接受Memory 的覆盖。这意味着我必须使用Memory 的ToArray 方法,它会生成数据的副本。这对我来说听起来不是很有效。
我知道可以通过将现有数组传递给其构造函数来创建 Memory 实例,如下所示:
byte[] buff = new byte[Mio];
Memory<byte> memory = new Memory<byte>(buff);
int bytesRead;
while ((bytesRead = await inputStream.ReadAsync(memory)) > 0) {
// Use `buff` to access the bytes
}
但是文档不清楚传递给构造函数的数组是否实际用作Memory 实例的底层存储。
因此,这是我的问题:
- 如何将
Memory中的数据直接提供给HashAlgorithm实例?我说的是派生自HashAlgorithm的类的任何 实例,而不是具体的SHA256 算法。与 Glacier 不同,我的实现不限于 SHA256。 - 存储在
Memory实例中的数据是否也可以在用于创建它的数组中访问? - 是否有另一种方法可以访问存储在
Memory实例中的数据作为数组,无需复制? - 如果做不到这一点,我如何才能使 SonarQube 中的外部问题静音(本例中为 Roslyn 警告)?我没有像普通声纳问题那样更改其状态的下拉菜单。
编辑添加有关代码工作原理的其他信息: 它是AWS's example of computing a Glacier Tree Hash 的第一部分,该部分计算文件中 1Mio 块的第一个哈希值。
这些是上面while循环的内容:
// Constructor of the class
// The class implements IDisposable to properly dispose of the Algorithm field
// Constructor is called like this
// `using TreeHash treeHash = new TreeHash(System.Security.Cryptography.SHA512.Create());`
public TreeHash(HashAlgorithm algo) {
this.Algorithm = algo;
}
// Chunk hash generation loop
// first part of the tree hash algorithm
byte[][] chunkHashes = new byte[numChunks][];
byte[] buff = new byte[Mio];
int bytesRead;
int idx = 0;
while ((bytesRead = await inputStream.ReadAsync(buff, 0, Mio)) > 0) {
chunkHashes[idx++] = this.ComputeHash(buff, bytesRead);
}
// Quick wrapper around the hash algorithm
// Also used by the second part of the tree hash computation
private byte[] ComputeHash(byte[] data, int count) => this.Algorithm.ComputeHash(data, 0, count);
我默认使用无前缀版本的哈希算法,但我可能会切换到托管版本。如果需要,该方法可以变为非async。
【问题讨论】:
-
TryComputeHash/TryHashData都接受ReadOnlySpan<byte>您可以将Memory<byte>的Span属性传递给它(带有任何需要的Slice'ing),它不会使任何副本,而是对原始数组(或子部分)进行操作。为了使用 Try 模式,您需要进行一些重组。真正对您的问题有帮助的是您如何使用HashAlgorithm的示例,尤其是关于当前缓冲区/它如何适合您现有代码的示例。这样我们就可以提供一个实际的答案 -
另外澄清一下,
TryHashData是使用非托管实现的各种HashAlgorithm类的static方法。即不以Managed结尾的类。你没有提到你正在使用哪个,但如果你还没有的话,我建议你使用xxxManaged版本。实例方法TryComputeHash可用于托管和非托管变体。 -
您已更新您的问题。但是您仍然没有提供足够的信息。请显示
Algorithm字段/属性的声明,以便我们可以看到它的声明/静态类型。您如何初始化它的示例也可能会有所帮助
标签: c# arrays sonarqube buffer filestream