gpt4 book ai didi

C#:将 COMP-3 压缩十进制转换为人类可读的值

转载 作者:太空狗 更新时间:2023-10-29 20:52:36 24 4
gpt4 key购买 nike

我有一系列来自大型机的 ASCII 平面文件,由 C# 应用程序处理。引入了带有压缩十进制 (COMP-3) 字段的新提要,需要将其转换为数值。

文件正在通过 FTP 传输,使用 ASCII 传输模式。我担心二进制字段可能包含将被解释为非常低的 ASCII 代码或控制字符而不是值的内容 - 或者更糟的是,可能会在 FTP 过程中丢失。

此外,字段被读取为字符串。我可能可以灵活地解决这部分问题(即某种流),但公司会给我回击。

要求是“Convert from HEX to ASCII”,但显然没有产生正确的值。任何帮助,将不胜感激;只要您能解释转换过程的逻辑,它就不必特定于语言。

最佳答案

我一直在关注许多关于将 Comp-3 BCD 数据从“遗留”大型机文件转换为可在 C# 中使用的文件的帖子。首先,我想说的是,我对其中一些帖子收到的回复并不感兴趣——尤其是那些基本上说“你为什么要用这些非 C#/C++ 相关的帖子来打扰我们”以及“如果您需要有关某种 COBOL 约定的答案,为什么不去访问面向 COBOL 的站点”。对我来说,这是完全的废话,因为可能需要很多年(不幸的是)让软件开发人员了解如何处理现实世界中存在的一些遗留问题。因此,即使我在这篇文章中因为以下代码而受到猛烈抨击,我仍将与您分享我必须处理的关于 COMP-3/EBCDIC 转换的真实世界经验(是的,我就是谈论“软盘、纸带、光盘包等...-我从 1979 年开始就是一名软件工程师”)。

首先 - 了解您从 IBM 等遗留大型机系统读取的任何文件都将以 EBCDIC 格式向您呈现数据,并且为了将任何数据转换为您可以处理的 C#/C++ 字符串您将不得不使用正确的代码页转换将数据转换为 ASCII 格式。如何处理这个问题的一个很好的例子是:

StreamReader readFile = new StreamReader(path, Encoding.GetEncoding(037);//037 = EBCDIC 到 ASCII 的转换。

这将确保您从此流中读取的任何内容都将转换为 ASCII,并可以以字符串格式使用。这包括 COBOL 声明的“分区十进制”(图 9)和“文本”(图 X)字段。但是,当读入 char[] 或 byte[] 数组时,这并不一定会将 COMP-3 字段转换为正确的“二进制”等价物。要做到这一点,您将获得正确翻译(甚至使用 UTF-8、UTF-16、默认或其他)代码页的唯一方法,您将要像这样打开文件:

FileStream fileStream = new FileStream(path, FIleMode.Open, FIleAccess.Read, FileShare.Read);

当然,“FileShare.Read”选项是“可选的”。

当您分离出要转换为十进制值的字段(如果需要,随后转换为 ASCII 字符串),您可以使用以下代码 - 这基本上是从 MicroSoft“UnpackDecimal”中窃取的您可以在以下位置发布:

http://www.microsoft.com/downloads/details.aspx?familyid=0e4bba52-cc52-4d89-8590-cda297ff7fbd&displaylang=en

我已经分离(我认为)这个逻辑中最重要的部分是什么,并将其合并为两个方法,您可以随心所欲地进行操作。出于我的目的,我选择将其保留为返回一个 Decimal 值,然后我可以用我想要的来做。基本上,该方法称为“unpack”,您向它传递一个 byte[] 数组(不超过 12 个字节)和作为 int 的比例,这是您希望在 Decimal 值中返回的小数位数。我希望这对你和我一样有用。

    private Decimal Unpack(byte[] inp, int scale)
{
long lo = 0;
long mid = 0;
long hi = 0;
bool isNegative;

// this nybble stores only the sign, not a digit.
// "C" hex is positive, "D" hex is negative, and "F" hex is unsigned.
switch (nibble(inp, 0))
{
case 0x0D:
isNegative = true;
break;
case 0x0F:
case 0x0C:
isNegative = false;
break;
default:
throw new Exception("Bad sign nibble");
}
long intermediate;
long carry;
long digit;
for (int j = inp.Length * 2 - 1; j > 0; j--)
{
// multiply by 10
intermediate = lo * 10;
lo = intermediate & 0xffffffff;
carry = intermediate >> 32;
intermediate = mid * 10 + carry;
mid = intermediate & 0xffffffff;
carry = intermediate >> 32;
intermediate = hi * 10 + carry;
hi = intermediate & 0xffffffff;
carry = intermediate >> 32;
// By limiting input length to 14, we ensure overflow will never occur

digit = nibble(inp, j);
if (digit > 9)
{
throw new Exception("Bad digit");
}
intermediate = lo + digit;
lo = intermediate & 0xffffffff;
carry = intermediate >> 32;
if (carry > 0)
{
intermediate = mid + carry;
mid = intermediate & 0xffffffff;
carry = intermediate >> 32;
if (carry > 0)
{
intermediate = hi + carry;
hi = intermediate & 0xffffffff;
carry = intermediate >> 32;
// carry should never be non-zero. Back up with validation
}
}
}
return new Decimal((int)lo, (int)mid, (int)hi, isNegative, (byte)scale);
}

private int nibble(byte[] inp, int nibbleNo)
{
int b = inp[inp.Length - 1 - nibbleNo / 2];
return (nibbleNo % 2 == 0) ? (b & 0x0000000F) : (b >> 4);
}

如果您有任何问题,请在此处发布 - 因为我怀疑我会像其他选择发布与当今问题相关的问题的其他人一样“发怒”...

谢谢,约翰 - 长者。

关于C#:将 COMP-3 压缩十进制转换为人类可读的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/142972/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com