【问题标题】:C#: how to read a line from a stream and then start reading it from beginning?C#:如何从流中读取一行,然后从头开始读取?
【发布时间】:2011-08-09 12:02:35
【问题描述】:

我需要从流中读取第一行以确定文件的编码,然后使用该编码重新创建流

以下代码无法正常工作:

var r = response.GetResponseStream();
var sr = new StreamReader(r);
string firstLine =  sr.ReadLine();
string encoding = GetEncodingFromFirstLine(firstLine);
string text = new StreamReader(r, Encoding.GetEncoding(encoding)).ReadToEnd();

文本变量不包含整个文本。由于某种原因,第一行和之后的几行被跳过了。

我尝试了所有方法:关闭 StreamReader、重置它、调用单独的 GetResponseStream……但没有任何效果。

我无法再次获取响应流,因为我是从 Internet 获取此文件的,并且再次重新下载它会降低性能。

更新

GetEncodingFromFirstLine() 如下所示:

public static string GetEncodingFromFirstLine(string line)
{
    int encodingIndex = line.IndexOf("encoding=");
    if (encodingIndex == -1)
    {
        return "utf-8";
    }
    return line.Substring(encodingIndex + "encoding=".Length).Replace("\"", "").Replace("'", "").Replace("?", "").Replace(">", "");
}

...

// true
Assert.AreEqual("windows-1251", GetEncodingFromFirstLine(@"<?xml version=""1.0"" encoding=""windows-1251""?>")); 

** 更新 2 **

我正在处理 XML 文件,文本变量被解析为 XML:

var feedItems = XElement.Parse(text);

【问题讨论】:

    标签: c# stream readline


    【解决方案1】:

    好吧,您是在要求它检测编码......这需要它来读取数据。那是从底层流中读取它,然后围绕同一流创建另一个 StreamReader

    我建议你:

    • 获取响应流
    • 将所有数据检索到一个字节数组(或MemoryStream)中
    • 检测编码(应该在 bytes 上执行,而不是文本 - 目前您已经通过创建 StreamReader 假设 UTF-8
    • 围绕字节数组创建一个MemoryStream,并围绕它创建一个StreamReader

    尚不清楚您的 GetEncodingFromFirstLine 方法是做什么的......或者这个文件到底是什么。更多信息可能会更容易为您提供帮助。

    编辑:如果这是为了加载一些 XML,请不要重新发明轮子。只需将流提供给现有的 XML 解析类之一,它将为您执行适当的检测。

    【讨论】:

    • @Skomski:谢谢 - 这使它更简单,因为 OP 根本不需要做这项工作。
    • 乔恩,谢谢你的回答!我已经尝试过检测字节编码,但没有奏效。我已经使用 GetEncodingFromFirstLine() 方法更新了帖子。
    • @Alex:你必须检测基于字节的编码,如果你真的想检测它。通过在字节周围创建StreamReader,您将丢失信息 - 因为它会强制 UTF-8 或UTF-16。但是,请参阅我的编辑 - 您根本不需要执行任何操作。只需将二进制数据提供给 XML 解析器即可。
    • 你是对的,我正在解析 XML。然而,当解析带有西里尔字符的 xml 文件时,我收到了不可读的东西,因为这些文件使用 Windows cp1251 编码。我需要检测编码并基于该编码创建 StreamReader。
    • @Alex:但 XML 解析器应该会为您处理,除非您说 XML 文件从根本上损坏。声明其编码的 XML 文件的全部意义在于允许解析器对您隐藏所有这些内容。
    【解决方案2】:

    您需要将流中的当前位置更改为开头。

    r.Position = 0;
    string text = new StreamReader(r, Encoding.GetEncoding(encoding)).ReadToEnd();
    

    【讨论】:

    • 流来自 HTTP 响应,因此不可搜索。并且 OP 想要检测编码,而您的代码假定编码是已知的
    【解决方案3】:

    我在这里找到了我的问题的答案:

    How can I read an Http response stream twice in C#?

    Stream responseStream = CopyAndClose(resp.GetResponseStream());
    // Do something with the stream
    responseStream.Position = 0;
    // Do something with the stream again
    
    
    private static Stream CopyAndClose(Stream inputStream)
    {
    const int readSize = 256;
    byte[] buffer = new byte[readSize];
    MemoryStream ms = new MemoryStream();
    
    int count = inputStream.Read(buffer, 0, readSize);
    while (count > 0)
    {
        ms.Write(buffer, 0, count);
        count = inputStream.Read(buffer, 0, readSize);
    }
    ms.Position = 0;
    inputStream.Close();
    return ms;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-11-12
      • 1970-01-01
      • 2015-04-11
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多