如何缓冲输入流直到它完成

时间:2011-10-12 18:05:44

标签: c# wcf stream

我正在实施一个接受图像流的wcf服务。但是当我运行它时,我正在获得异常。因为它试图在流完成之前获取流的长度。所以我想做的是缓冲流直到完成。但是我找不到任何如何做到这一点的例子......

任何人都可以帮忙吗?

到目前为止我的代码:

    public String uploadUserImage(Stream stream)
    {
          Stream fs = stream;

          BinaryReader br = new BinaryReader(fs);

          Byte[] bytes = br.ReadBytes((Int32)fs.Length);// this causes exception

          File.WriteAllBytes(filepath, bytes);
    }

4 个答案:

答案 0 :(得分:6)

您应该从流中读取,直到它返回“已完成”,而不是尝试获取长度。在.NET 4中,这非常简单:

// Assuming we *really* want to read it into memory first...
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
File.WriteAllBytes(filepath, memoryStream);

在.NET 3.5中,没有CopyTo方法,但您可以自己编写类似的东西:

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}

然而,现在我们有了复制流的东西,为什么还要先将它全部读入内存呢?我们直接把它写到一个文件:

using (FileStream output = File.OpenWrite(filepath))
{
    CopyStream(stream, output); // Or stream.CopyTo(output);
}

答案 1 :(得分:1)

我不确定你要回来的东西(或不回来),但是这样的东西可能适合你:

public String uploadUserImage(Stream stream) {
  const int KB = 1024;
  Byte[] bytes = new Byte[KB];
  StringBuilder sb = new StringBuilder();
  using (BinaryReader br = new BinaryReader(stream)) {
    int len;
    do {
      len = br.Read(bytes, 0, KB);
      string readData = Encoding.UTF8.GetString(bytes);
      sb.Append(readData);
    } while (len == KB);
  }
  //File.WriteAllBytes(filepath, bytes);
  return sb.ToString();
}

我相信字符串最多可以容纳2 GB。

答案 2 :(得分:0)

试试这个:

    using (StreamWriter sw = File.CreateText(filepath))
    {
        stream.CopyTo(sw);
        sw.Close();
    }

答案 3 :(得分:-1)

Jon Skeets使用缓冲区读取对.Net 3.5及以下版本的答案实际上是错误地完成的。

两次读取之间未清除缓冲区,这可能导致任何返回小于8192的读取出现问题,例如,如果第二次读取读取192个字节,则第一次读取的最后8000个字节仍在缓冲区中然后将其返回到流中。

我在下面的代码中为其提供一个Stream,它将返回IEnumerable数组。
使用它,您可以对其进行每个操作并将其写入MemoryStream,然后使用.GetBuffer()以编译后的合并字节[]结尾。

private IEnumerable<byte[]> ReadFullStream(Stream stream) {
   while(true) {
        byte[] buffer = new byte[8192];//since this is created every loop, its buffer is cleared
        int bytesRead = stream.Read(buffer, 0, buffer.Length);//read up to 8192 bytes into buffer
        if (bytesRead == 0) {//if we read nothing, stream is finished
            break;
        }
        if(bytesRead < buffer.Length) {//if we read LESS than 8192 bytes, resize the buffer to essentially remove everything after what was read, otherwise you will have nullbytes/0x00bytes at the end of your buffer
            Array.Resize(ref buffer, bytesRead);
        }
        yield return buffer;//yield return the buffer data
    }//loop here until we reach a read == 0 (end of stream)
}