【问题标题】:StreamReader ReadToEnd() returns empty string on first attemptStreamReader ReadToEnd() 在第一次尝试时返回空字符串
【发布时间】:2010-12-16 13:53:32
【问题描述】:

我知道以前在 Stackoverflow 上有人问过这个问题,但找不到解释。

当我尝试从压缩字节数组中读取字符串时,第一次尝试得到一个空字符串,第二次我成功并得到了字符串。

代码示例:

public static string Decompress(byte[] gzBuffer)
{
    if (gzBuffer == null)
        return null;
    using (var ms = new MemoryStream(gzBuffer))
    {
        using (var decompress = new GZipStream(ms, CompressionMode.Decompress))
        {
            using (var sr = new StreamReader(decompress, Encoding.UTF8))
            {
                string ret = sr.ReadToEnd();
                // this is the extra check that is needed !?
                if (ret == "")
                    ret = sr.ReadToEnd();
                return ret;
            }
        }
    }
}

感谢所有建议。 - 维克多·卡塞尔

【问题讨论】:

  • 我认为您不需要检查,它看起来多余。

标签: c# streamreader


【解决方案1】:

我发现了错误。正如迈克尔在压缩程序中建议的那样。我错过了在 GZipStream 上调用 Close()。

public static byte[] Compress(string text)
{
    if (string.IsNullOrEmpty(text))
        return null;

    byte[] raw = Encoding.UTF8.GetBytes(text);
    using (var ms = new MemoryStream())
    {
        using (var compress = new GZipStream (ms, CompressionMode.Compress))
        {
            compress.Write(raw, 0, raw.Length);
            compress.Close();

            return ms.ToArray();
        }
    } 
}

发生的情况是数据似乎以错误的状态保存,需要稍后在解压缩例程中调用两次 ReadToEnd() 以提取相同的数据。很奇怪!

【讨论】:

    【解决方案2】:

    尝试在string ret = sr.ReadToEnd();之前添加ms.Position = 0

    【讨论】:

    • 我试过了,但没有帮助,我也试过 ms.Seek(0, SeekOrigin.Begin)。
    【解决方案3】:

    gzBuffer 来自哪里?您是否还编写了生成压缩数据的代码?

    也许您拥有的缓冲区数据无效或不完整,或者它由多个串联在一起的 deflate 流组成。

    【讨论】:

    • 我发现了这个错误。正如迈克尔在压缩程序中建议的那样。我错过了在 GZipStream 上调用 Close()。 compress.Write(raw, 0, raw.Length);压缩。关闭();返回 ms.ToArray();发生的情况是,数据似乎以错误的状态保存,需要稍后在解压缩例程中调用两次 ReadToEnd() 以提取相同的数据。很奇怪!
    【解决方案4】:

    我希望这会有所帮助。

    对于字节数组:

    static byte[] CompressToByte(string data)
    {
        MemoryStream outstream = new MemoryStream();
        GZipStream compressionStream =
        new GZipStream(outstream, CompressionMode.Compress, true);
        StreamWriter writer = new StreamWriter(compressionStream);
        writer.Write(data);
        writer.Close();
        return StreamToByte(outstream);
    }
    
    static string Decompress(byte[] data)
    {
        MemoryStream instream = new MemoryStream(data);
        GZipStream compressionStream =
        new GZipStream(instream, CompressionMode.Decompress);
        StreamReader reader = new StreamReader(compressionStream);
        string outtext = reader.ReadToEnd();
        reader.Close();
        return outtext;
    }
    
    public static byte[] StreamToByte(Stream stream)
    {
        stream.Position = 0;
        byte[] buffer = new byte[128];
        using (MemoryStream ms = new MemoryStream())
        {
            while (true)
            {
                int read = stream.Read(buffer, 0, buffer.Length);
                if (!(read > 0))
                    return ms.ToArray();
                ms.Write(buffer, 0, read);
            }
        }
    }

    您可以将if(!(read > 0)) 替换为if(read <= 0)。 出于某种原因,if(read <= 0) 上面没有正确显示。

    对于流:

    static Stream CompressToStream(string data)
    {
        MemoryStream outstream = new MemoryStream();
        GZipStream compressionStream =
        new GZipStream(outstream, CompressionMode.Compress, true);
        StreamWriter writer = new StreamWriter(compressionStream);
        writer.Write(data);
        writer.Close();
        return outstream;
    }
    
    static string Decompress(Stream data)
    {
        data.Position = 0;
        GZipStream compressionStream =
        new GZipStream(data, CompressionMode.Decompress);
        StreamReader reader = new StreamReader(compressionStream);
        string outtext = reader.ReadToEnd();
        reader.Close();
        return outtext;
    }

    【讨论】:

      【解决方案5】:

      The MSDN Page on the function 提到以下内容:

      如果当前方法抛出 OutOfMemoryException,则读取器在底层 Stream 对象中的位置会提前该方法能够读取的字符数,但已读取到内部 ReadLine 缓冲区的字符将被丢弃。如果在将数据读入缓冲区后操作底层流的位置,则底层流的位置可能与内部缓冲区的位置不匹配。要重置内部缓冲区,请调用 DiscardBufferedData 方法;但是,此方法会降低性能,并且仅在绝对必要时才应调用。

      也许尝试在您的ReadToEnd() 之前调用DiscardBufferedData() 并查看它的作用(我知道您没有遇到异常,但这是我能想到的全部...)?

      【讨论】:

      • 不,调用 DiscarBufferedData() 也没有帮助。
      猜你喜欢
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      • 2012-06-16
      • 2015-09-11
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 2023-01-13
      相关资源
      最近更新 更多