【问题标题】:Stream.Length throws NotSupportedExceptionStream.Length 抛出 NotSupportedException
【发布时间】:2011-03-23 08:41:01
【问题描述】:

在发送到我的 WCF 方法的 Stream 对象上尝试 stream.Length 时出现错误。

Unhandled Exception!
 Error ID: 0
 Error Code: Unknown
 Is Warning: False
 Type: System.NotSupportedException
 Stack:    at System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.get_Length()

如何获得流的长度?有什么例子吗?

【问题讨论】:

  • Stream类是抽象的,你用的是什么派生的Stream类?另外,如果可能,请发布导致问题的代码?

标签: c# .net stream notsupportedexception


【解决方案1】:

Stream.Length 仅适用于可搜索的 Stream 实现。您通常可以检查Stream.CanSeek 是否为真。许多流,因为它们正在流式传输,因此具有无法提前知道长度的性质。

如果您必须知道长度,您可能需要实际缓冲整个流,提前将其加载到内存中。

【讨论】:

  • HttpClient.GetStreamAsync(url) 是怎么回事?它将具有 Length 属性集,但不可搜索。那么我是否必须使用 try-catch 测试 Stream.Length 属性的值?
  • @BrunoZell 在 HTTP 请求/响应流的情况下:不能信任 Content-Length 标头(“永远不要信任 [客户端|管道的另一端]!”):连接可能是中止,否则服务器可能会通过 TCP 连接推送比客户端预期更多的数据。
【解决方案2】:

这就是我的工作:

// Return the length of a stream that does not have a usable Length property
public static long GetStreamLength(Stream stream)
{
    long originalPosition = 0;
    long totalBytesRead = 0;

    if (stream.CanSeek)
    {
        originalPosition = stream.Position;
        stream.Position = 0;
    }

    try
    {
        byte[] readBuffer = new byte[4096];
        int bytesRead;

        while ((bytesRead = stream.Read(readBuffer, 0, 4096)) > 0)
        {
            totalBytesRead += bytesRead;
        }

    }
    finally
    {
        if (stream.CanSeek)
        {
            stream.Position = originalPosition;
        }
    }

    return totalBytesRead;
}

【讨论】:

  • 警告:如果您的文件大小可能超过 2 GB (~int.MaxValue),请使用 long 类型为 totalBytesRead
【解决方案3】:

我在使用 WCF 服务时遇到了同样的问题。我需要获取 POST 消息的内容,并在我的方法中使用 Stream 参数来获取消息正文的内容。一旦我得到流,我想一次读取它的所有内容,并且需要知道我需要什么大小的字节数组。所以,在分配数组时,我会调用System.IO.Stream.Length 并得到OP 提到的异常。是不是你需要知道流的长度才能读取整个流的内容?

您实际上可以使用System.IO.StreamReader 将流的全部内容读入字符串。如果您仍然需要知道流的大小,可以获取结果字符串的长度。这是我如何解决这个问题的代码:

    [OperationContract]
    [WebInvoke(UriTemplate = "authorization")]
    public Stream authorization(Stream body)
    {
        // Obtain the token from the body
        StreamReader bodyReader = new StreamReader(body);
        string bodyString = bodyReader.ReadToEnd();
        int length = bodyString.Length; // (If you still need this.)
       // Do whatever you want to do with the body contents here. 
    }

【讨论】:

    【解决方案4】:

    您无法始终获得流的长度。例如,在网络流的情况下,找出长度的唯一方法是从中读取数据,直到它关闭。

    你想做什么?您是否可以从流中读取数据直到它耗尽,然后将数据复制到 MemoryStream 中?

    【讨论】:

    • @Nevin:流中还有什么其他情况?基本上,如果不通过读取来更改状态,您将无法获取此信息。
    【解决方案5】:

    如果流不支持搜索,则并不总是可以获得流的长度。请参阅Stream class 上的异常表。

    例如,连接到另一个进程(网络流、标准输出等)的流可以产生任意数量的输出,具体取决于其他进程的编写方式,并且框架无法计算出多少有数据。

    在一般情况下,您只需读取所有数据直到流结束,然后计算出您已读取了多少。

    【讨论】:

      【解决方案6】:

      TcpClient.EndRead() 应该返回流中的字节数。

      --编辑,当然你需要使用TCP Stream

      【讨论】:

        猜你喜欢
        • 2013-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多