首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >StreamReader和EBCDIC的奇怪行为:为什么?

StreamReader和EBCDIC的奇怪行为:为什么?
EN

Stack Overflow用户
提问于 2015-02-17 10:48:14
回答 2查看 1.9K关注 0票数 2

背景:我必须编写一个应用程序,该应用程序接受一个设计糟糕的EBCDIC文件,其中包含二进制数据,其中使用了ASCII行终止符,有时该二进制数据碰巧包含ASCII CRLF,这会导致该行不正确地拆分。我需要采用这个旧的文件格式,并在每个记录的末尾删除CRLF。

使用带有StreamReader编码的IBM037似乎会导致ReadLine()方法只将\r作为行的末尾而不是我所期望的\r\n,因此从ReadLine返回的每个字符串(第一个字符串之后)都以LF (0A in ASCII中的0A)开头。

再现问题的示例程序:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

class Program
{
  static void Main(string[] args)
  {
    //generate example EBCDIC data
    List<byte> bytes = new List<byte>();
    Encoding EBCDIC = Encoding.GetEncoding("IBM037");
    bytes.AddRange(Encoding.Convert(Encoding.ASCII, EBCDIC, Encoding.ASCII.GetBytes("Some nice ascii text")));
    bytes.AddRange(new byte[] { (byte)'\r', (byte)'\n' });
    bytes.AddRange(Encoding.Convert(Encoding.ASCII, EBCDIC, Encoding.ASCII.GetBytes("Some more nice ascii text")));

    //read it using StreamReader
    using(MemoryStream ms = new MemoryStream(bytes.ToArray()))
    using (StreamReader reader = new StreamReader(ms, EBCDIC))
    {
      string line = string.Empty;
      while ((line = reader.ReadLine()) != null)
      {
        EBCDIC.GetBytes(line).ToList().ForEach(c => Console.Write(c));
        Console.WriteLine();
      }
    }
    Console.ReadLine();
  }
}

产出应如下:

代码语言:javascript
复制
226150148133641491371311336412916213113713764163133167163
1022615014813364148150153133641491371311336412916213113713764163133167163

第二行开头的10不应该在那里,因为那是来自CRLF序列的LF。

我对ReadLine方法的理解是:

行被定义为一个字符序列,后面跟着一个行提要("\n")、一个回车("\r")或一个回车返回,后面紧跟一个行提要("\r\n")。返回的字符串不包含终止运输、返回或行提要。来源

它没有提到编码改变的任何地方,因此它应该在我的数据中读取完整的CRLF,而不仅仅是CR。

更新:我已经解决了这个问题,并且实现了我自己的读取数据的方法,但是我的问题仍然是:为什么ReadLine不按照它在tin上说的做呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-02-19 08:50:25

(byte)'\r'(byte)'\n'填充到流中,然后告诉StreamReader是用EBCDIC编码的。

(byte) '\r'的值是0x0d,这恰好是ASCII和EBCDIC中的回车。

(byte) '\n'的值为0x0a,这是ASCII中的行提要,但在EBCDIC中不是行提要。

如果查看EBCDIC编码器类如何将值0x0a解码为.NET Unicode char类型,您会发现Unicode char的数值为142 (或0x8e)。而且那个角色不是一个行提要。(我不知道为什么会被解码为142)。

您可以在第二行的开头看到" 10“,并不是因为那里有一个行提要,而是因为值142的字符被重新编码回值为10的EBCDIC字节(在子表达式EBCDIC.GetBytes(line)中)。

因此,简单地回答您的问题,ReadLine()只看到回车,而不是回车,后面跟着行提要。

while循环更改为如下所示:

代码语言:javascript
复制
while ((line = reader.ReadLine()) != null)
{
    line.ToList().ForEach(c => { Console.Write(c); Console.Write(" "); });
    Console.WriteLine();
    line.ToList().ForEach(c => { Console.Write(Convert.ToInt32(c)); Console.Write(" "); });
    Console.WriteLine();
    EBCDIC.GetBytes(line).ToList().ForEach(c => { Console.Write(c); Console.Write(" "); });
    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine();
}

您将得到第二行的输出,它将行(从EBCDIC转换而来)显示为字符,这些字符的Unicode值,最后将这些字符的值转换回EBCDIC:

代码语言:javascript
复制
? S o m e   m o r e   n i c e   a s c i i   t e x t
142 83 111 109 101 32 109 111 114 101 32 110 105 99 101 32 97 115 99 105 105 32 116 101 120 116
10 226 150 148 133 64 148 150 153 133 64 149 137 131 133 64 129 162 131 137 137 64 163 133 167 163
票数 2
EN

Stack Overflow用户

发布于 2015-02-19 07:07:38

MSDN论坛上,我无意中发现了以下讨论:

根据本文件,"EBCDIC lineFeed映射导致无效字符“一节,在底部附近,IBM037有两个行提要代码,0x15和0x25。.NET似乎使用0x25: System.Text.Encoding.GetEncoding("IBM037").GetBytes("hello\r\n");字节= byte[]字节 我看到了另一个把它映射到0x15的网页。难怪ASCII赢了..。

维基百科 von 037的检查证实,Byte 21 (0x15)确实被定义为"Newline“,37 (0x25)定义为"Line feed”,其中Byte 13 (0x0D)是良好的“回车”。

所以ASCII不是EBCDIC 037的一个子集。

因此,您的测试代码有缺陷,因为当您这样做时,将字节0x10和0x13添加到应该被EBCDIC编码的字节中:

代码语言:javascript
复制
bytes.AddRange(new byte[] { (byte)'\r', (byte)'\n' });

相反,请尝试以下几点:

代码语言:javascript
复制
bytes.AddRange(Encoding.Convert(Encoding.ASCII, EBCDIC, Encoding.ASCII.GetBytes(
    "Some nice ascii text\r\nSome more nice ascii text")));

读取结果字节的工作原理是应该的,因为"\r\n“被转换为EBCDIC的字节13和37。然后,ReadLine()正确地跳过字节37,这是EBCDIC的"Newline“。

这是因为ReadLine() 比较Unicode字符,而不是字节。EBCDIC "NewLine“(0x25)字节被解码为Unicode字符'\n‘。

结论

  1. 一切都正常运作。
  2. 并非所有编码都有ASCII作为子集。
  3. ReadLine()处理Unicode字符,因此它必须是编码/解码问题。
  4. 检查原始问题的输入数据。它可能包含无效的(对于EBCDIC)换行符。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28560196

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档