【问题标题】:How to copy one Stream to a byte array with the smallest C# code?如何使用最小的 C# 代码将一个 Stream 复制到一个字节数组?
【发布时间】:2010-10-31 08:00:24
【问题描述】:

到目前为止,我计算的是 12 个 LoC。你能把它变小吗?

using (Stream fileStream = File.OpenRead(fileName))
{
    using (BinaryReader binaryReader = new BinaryReader(fileStream))
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            byte[] buffer = new byte[256];
            int count;
            int totalBytes = 0;
            while ((count = binaryReader.Read(buffer, 0, 256)) > 0)
            {
                memoryStream.Write(buffer, 0, count);
                totalBytes += count;
            }
            memoryStream.Position = 0;
            byte[] transparentPng = new byte[totalBytes];
            memoryStream.Read(transparentPng, 0, totalBytes);
        }
    }
}

【问题讨论】:

    标签: c# .net stream


    【解决方案1】:

    怎么样:

    byte[] result = File.ReadAllBytes(fileName);
    

    【讨论】:

    • 虽然它当然只适用于文件......它匹配原始问题中的代码,但不匹配问题的标题:)
    • 好点。也许如果我以后觉得无聊,我会用一个接受开放流作为输入的函数来表达这一点——对于所有的代码 sn-ps,还没有人费心把函数签名放在外面。
    • 正如我在回答中所展示的,对于您知道其长度的流来说,这并不复杂。对于未知长度的流,您可能可以编写一个 3/4 行扩展方法来完成这项工作。
    【解决方案2】:

    有一种静态方法可以在一次调用中为您完成此操作。

    var data = File.ReadAllBytes(fileName);
    

    或者,适用于任何Stream(返回其长度)的方法是:

    byte[] data;
    using (var br = new BinaryReader(stream))
        data = br.ReadBytes((int)stream.Length);
    

    对于没有明确定义长度的流(例如NetworkStream),因此在调用stream.Length 时会引发异常,这当然不起作用。 Jon Skeet 的答案中提出的稍微复杂一点的解决方案就是您可能想要的。

    【讨论】:

    • 数据 = binaryReader.ReadBytes(stream.Length);应该是 data = br.ReadBytes(stream.Length);
    • 有人试过吗? br.ReadBytes 接受一个 int 参数,而 stream.Length 是一个 long。它不会编译。
    • 它很容易通过简单的演员阵容修复。如果流的长度比最大 Int32 值长,你真的不想这样做!
    【解决方案3】:

    虽然不减少 LOC(我永远不会将此作为主要动机),但您可以像这样折叠使用:

    using (Stream fileStream = File.OpenRead(fileName))
    using (BinaryReader binaryReader = new BinaryReader(fileStream))
    using (MemoryStream memoryStream = new MemoryStream())
    {
        byte[] buffer = new byte[256];
        int count;
        int totalBytes = 0;
        while ((count = binaryReader.Read(buffer, 0, 256)) > 0)
        {
            memoryStream.Write(buffer, 0, count);
            totalBytes += count;
        }
        memoryStream.Position = 0;
        byte[] transparentPng = new byte[totalBytes];
        memoryStream.Read(transparentPng, 0, totalBytes);    
    }
    

    【讨论】:

    • “如果它有效,为什么这很重要?”只要您不必维护代码就没有关系;-)
    • +1 表示“为什么重要...”不过,在这种情况下,File.ReadAllBytes 很难被击败。
    • 我试图(糟糕地)提出的观点是,目标不应该是降低 LOC,而是提高清晰度。我每天都会使用 30 行清晰的代码,而不是 4 行令人费解的疯狂。
    【解决方案4】:

    在这里减少代码行非常简单(同时仍然可以处理任意流,而不仅仅是文件):

    using (Stream fileStream = File.OpenRead(fileName))
    using (MemoryStream memoryStream = new MemoryStream())
    {
        int byteRead;
        while ((byteRead = fileStream.ReadByte()) != -1)
        {
            memoryStream.WriteByte(byteRead);
        }
        return memoryStream.ToArray();
    }
    

    显然,读取缓冲区比一次读取一个字节要高效,但这会减少语句的数量(因为您不需要同时声明缓冲区和一个变量来保存 Stream 的返回值)。调用MemoryStream.ToArray() 比读入一个新构造的数组更简单。

    不过,使用缓冲区会更好。请注意,我们真的不需要 BinaryReader:

    using (Stream fileStream = File.OpenRead(fileName))
    using (MemoryStream memoryStream = new MemoryStream())
    {
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            memoryStream.Write(buffer, 0, bytesRead);
        }
        return memoryStream.ToArray();
    }
    

    如果你想真的残忍,我们可以减少using 语句的数量(使用任一解决方案):

    using (Stream fileStream = File.OpenRead(fileName),
                  memoryStream = new MemoryStream())
    {
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            memoryStream.Write(buffer, 0, bytesRead);
        }
        return ((MemoryStream)memoryStream).ToArray();
    }
    

    但这很讨厌:)

    当然,另一种选择是使用诸如MiscUtil 之类的库,它具有从流中完全读取的方法:) 实用方法可以像这样简单:

    public static byte[] ReadFully(this Stream stream)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                memoryStream.Write(buffer, 0, bytesRead);
            }
            return memoryStream.ToArray();
        }
    }
    

    请注意,这个从不关闭流 - 调用者应该这样做。

    【讨论】:

      【解决方案5】:

      只需使用StreamCopyTo 方法复制到MemoryStream,并获取数组:

      using (var fileStream = File.OpenRead(fileName))
      {
          using (var memoryStream = new MemoryStream())
          {
              fileStream.CopyTo(memoryStream);
              memoryStream.Seek(0, SeekOrigin.Begin);
      
              byte[] transparentPng = memoryStream.ToArray();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2015-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多