【问题标题】:Hash a file as its being recived在接收文件时散列文件
【发布时间】:2015-10-22 12:41:14
【问题描述】:

最终目标: 用户正在将大量不同大小的文件上传到我的网站。而且我不想在磁盘上重复文件。

我一直使用的解决方案是文件上传时的简单 SH1 哈希。使用这样的代码:

public static string HashFile(string FileName)
{
   using (FileStream stream = File.OpenRead(FileName))
   {
      SHA1Managed sha = new SHA1Managed();
      byte[] checksum = sha.ComputeHash(stream);

      string sendCheckSum = BitConverter.ToString(checksum).Replace("-",string.Empty);
                    return sendCheckSum;
   } 
}

这对于较小的文件“工作”很好,但是当文件为 30gb 时它会很痛苦。所以我想在从客户端接收文件时对文件进行哈希处理。我从客户端以“块”的形式获取文件,块的大小并不总是静态的。

接收文件的代码。

int chunk = context.Request["chunk"] != null ? int.Parse(context.Request["chunk"]) : 0;
int chunks = context.Request["chunks"] != null ? int.Parse(context.Request["chunks"]) : 0;
string fileName = context.Request["name"] != null ? context.Request["name"] : string.Empty;

HttpPostedFile fileUpload = context.Request.Files[0];    
string fullFilePath = Path.Combine(SiteSettings.UploadTempFolder, fileName);
using (var fs = new FileStream(fullFilePath, chunk == 0 ? FileMode.Create : FileMode.Append))
{
    var buffer = new byte[fileUpload.InputStream.Length];
    fileUpload.InputStream.Read(buffer, 0, buffer.Length);

    fs.Write(buffer, 0, buffer.Length);
    **// Here i want the hash, when i have the file data in memory.**
}

【问题讨论】:

  • 你的意思是SHA-1 吗?见this,SHA-1也有这样的方法。
  • 这似乎是最好的方式@Sinatr,将其作为回复发布:)
  • 你成功了吗?然后自己为未来的访问者发布答案。
  • 是的,我想你想要 presius 互联网积分 :)

标签: c# hash


【解决方案1】:

您始终可以创建自己的流:)

public class ActionStream : Stream
{
    private readonly Stream _innerStream;
    private readonly Action<byte[], int, int> _readAction;

    public ActionStream(Stream innerStream, Action<byte[], int, int> readAction)
    {
        _innerStream = innerStream;
        _readAction = readAction;
    }

    public override bool CanRead => true;
    public override bool CanSeek => false;
    public override bool CanWrite => false;
    public override long Length => _innerStream.Length;
    public override long Position
    {
        get { return _innerStream.Position; }
        set { throw new NotSupportedException(); }
    }

    public override void Flush() { }

    public override int Read(byte[] buffer, int offset, int count)
    {
        var bytesRead = _innerStream.Read(buffer, offset, count);

        _readAction(buffer, offset, bytesRead);

        return bytesRead;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotSupportedException();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _innerStream.Dispose();
        }

        base.Dispose(disposing);
    }

    public override void SetLength(long value) { throw new NotSupportedException(); }

    public override void Write(byte[] buffer, int offset, int count) 
    { 
      throw new NotSupportedException(); 
    }
}

这允许您将正在执行的两个流操作绑定在一起:

using (var fs = new FileStream(path, chunk == 0 ? FileMode.Create : FileMode.Append))
{
  var as = new ActionStream(fileUpload.InputStream,
    (buffer, offset, bytesRead) =>
    {
      fs.Write(buffer, offset, bytesRead);
    });

  var sha = new SHA1Managed();
  var checksum = sha.ComputeHash(as);
}

这假设SHA1Manager 按顺序读取输入流的每一个字节——你应该检查一下。不过,我很确定这就是它的工作原理:)

【讨论】:

  • 重写的 Flush() 应该调用 base.Flush();
  • @ipavlu Stream.Flush 是抽象的,所以不。充其量,它可以抛出。但无论如何,这个问题没有实际意义,因为我们不支持写作。
【解决方案2】:

这是一个剪切和粘贴来自:

Compute a hash from a stream of unknown length in C#

MD5 与其他哈希函数一样,不需要两次传递。

开始:

HashAlgorithm hasher = ..;
hasher.Initialize();

随着每个数据块的到达:

byte[] buffer = ..;
int bytesReceived = ..;
hasher.TransformBlock(buffer, 0, bytesReceived, null, 0);

完成并检索哈希:

hasher.TransformFinalBlock(new byte[0], 0, 0);
byte[] hash = hasher.Hash;

此模式适用于从HashAlgorithm 派生的任何类型,包括MD5CryptoServiceProviderSHA1Managed

HashAlgorithm 还定义了一个方法ComputeHash,它接受一个Stream 对象;但是,此方法将阻塞线程,直到流被消耗。使用TransformBlock 方法允许在数据到达时计算“异步哈希”,而不会使用线程。

【讨论】:

    猜你喜欢
    • 2014-03-30
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2011-07-28
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多