【问题标题】:StreamReader from MemoryStream来自 MemoryStream 的 StreamReader
【发布时间】:2018-02-27 05:25:20
【问题描述】:

我正在从 base64 字符串解码 csv 文件:

byte[] input;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write))
using (var tr = new StreamWriter(cs))
{
    tr.Write(data);
    tr.Flush();
    input = ms.ToArray();
}

如何简单地按字符串读取解码文件? 例如,类似于我们如何从HttpWebResponse 流中读取文件:

using (StreamReader input = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(1251), true))
{
    while (!input.EndOfStream)
    {
         string row = input.ReadLine();
    }
}

【问题讨论】:

  • @Nkosi 将内存流传递给阅读器的方式正是我所要求的
  • @Nkosi 您的解决方案是可行的,即使不是那么完美。我必须从 base64 字符串解析 csv 文件并将数据写入数据库。
  • 您知道,从技术上讲,csv 格式允许在单元格内换行。如果您的输入可能来自转换后的电子表格文件,您可以查看a more advanced approach,而不是逐行阅读。

标签: c# stream .net-4.6


【解决方案1】:

不用麻烦转换为数组,只需将内存流位置重置为0,然后将内存流传递给读取器,然后读取结束。

using (var ms = new MemoryStream()) {
    using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write)) {
        using (var tr = new StreamWriter(cs)) {
            tr.Write(data);
            tr.Flush();
            ms.Position = 0;
            using (var reader = new StreamReader(ms, Encoding.GetEncoding(1251), true)) {
                string csv = reader.ReadToEnd();
                //OR
                //while (!reader.EndOfStream) {
                //    var line = reader.ReadLine();
                //}
            }
        }
    }
}

这是另一种选择

byte[] input;
using (var ms = new MemoryStream()) {
    using (var cs = new CryptoStream(ms, new FromBase64Transform(), CryptoStreamMode.Write)) {
        using (var tr = new StreamWriter(cs)) {
            tr.Write(data);
            tr.Flush();
            input = ms.ToArray();
        }
    }
}
using (var ms = new MemoryStream(input)) {
    using (var reader = new StreamReader(ms, Encoding.GetEncoding(1251), true)) {
        string csv = reader.ReadToEnd();
        //OR
        //while (!reader.EndOfStream) {
        //    var line = reader.ReadLine();
        //}
    }
}

【讨论】:

  • 我一直在读入 MemoryStream,然后需要从中读取,并且在我的流阅读器中不断让 ReadLine() 返回 null。当我看到你在内存流中将位置设置为 0 时,我的“你一定是在开玩笑”的时刻......不敢相信它不会默认从流中内存流的开头读取读者。非常感谢您的回答!
【解决方案2】:

您可以从一个数组开始初始化MemoryStream;那么您不必向流中写入任何内容。由于 Base64 根据定义是纯 ascii 文本,因此您只需使用 ASCII 编码将输入字符串转换为字节即可。

不过,如果您要解析 CSV,则有比逐行读取文本更好的输出选项。从技术上讲,CSV 格式可以在 inside 字段中包含换行符,几乎所有从电子表格文件(如 MS Excel)写入 CSV 的东西都支持这一功能。为了支持这一点,逐行阅读方法过于简单。 .Net 框架包含一个本机 CSV 阅读器,尽管它很好地隐藏在 Microsoft.VisualBasic 类中。但是,由于 .Net 是一个框架,因此没有什么可以阻止您添加引用并在 C# 中使用它。班级是TextFieldParser,来自Microsoft.VisualBasic.FileIO

public static List<String[]> ParseBase64Csv(String data, Encoding encoding, Char separator, Boolean ignoreEmptyLines)
{
    List<String[]> splitLines = new List<String[]>();
    using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(data)))
    using (FromBase64Transform tr = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces))
    using (CryptoStream cs = new CryptoStream(ms, tr, CryptoStreamMode.Read))
    using (StreamReader sr = new StreamReader(cs, encoding))
    using (TextFieldParser tfp = new TextFieldParser(sr))
    {
        tfp.TextFieldType = FieldType.Delimited;
        tfp.Delimiters = new String[] { separator.ToString() };
        while (true)
        {
            try
            {
                String[] curLine = tfp.ReadFields();
                if (curLine == null)
                    break;
                if (ignoreEmptyLines && (curLine.Length == 0 || curLine.All(x => String.IsNullOrEmpty(x) || String.IsNullOrEmpty(x.Trim()))))
                    continue;
                splitLines.Add(curLine);
            }
            catch (MalformedLineException mfle)
            {
                // do something with errors here.
            }
        }
    }
    return splitLines;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 2020-06-30
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多