【问题标题】:EBCDIC to ASCII conversion, handling numeric valuesEBCDIC 到 ASCII 转换,处理数值
【发布时间】:2013-01-09 07:02:37
【问题描述】:

我正在尝试将文件从 ECDIC 转换为 ASCII 格式,但遇到了一个有趣的问题。这些文件包含固定长度的记录,其中一些字段是有符号二进制整数(在记录布局中描述为 B4)和 长精度数字值(在记录中描述为 L8布局)。我已经能够毫无问题地转换字符数据,但我不确定如何转换这些数值。来自原始系统的参考手册(IBM 5110),字段如下所述。

B 表示数字数据项的长度(2、4 或 8 字节) 要转换为的定点有符号二进制整数格式 BASIC 内部数据格式。对于记录 I/O 文件输入,接下来的 2, 记录中的 4 或 8 个字节包含有符号二进制值 由系统转换为内部数据格式并分配给 在 READ FILE 或 REREAD FILE 语句中指定的变量使用 一个 FORM 语句。

L 表示数值的长精度(8 个字符)。为了 输入,该条目表示一个八位长精度 记录中的值将被分配而不转换为 在 READ FILE 或 REREAD 中指定的相应数值变量 FILE 语句。

编辑:这是我用于转换的代码

private void ConvertFile(EbcdicFile file)
{
    if (file == null) return;

    var filePath = Path.Combine(file.Path, file.FileName);
    if (!File.Exists(filePath))
    {
        this.Logger.Info(string.Format("Cannot convert file {0}. It does not exist.", filePath));
        return;
    }

    var ebcdic = Encoding.GetEncoding(37);
    string convertedFilepath = Path.Combine(file.Path, file.ConvertedFileName);
    byte[] fileData = File.ReadAllBytes(filePath);

    if (!file.HasNumericFields)
        File.WriteAllBytes(convertedFilepath, Encoding.Convert(ebcdic, Encoding.ASCII, fileData));
    else
    {
        var convertedFileData = new List<byte>();
        for (int position = 0; position < fileData.Length; position += file.RecordLength)
        {
            var segment = new ArraySegment<byte>(fileData, position, file.RecordLength);
            file.Fields.ForEach(field =>
                {
                    var fieldSegment = segment.Array.Skip(segment.Offset + field.Start - 1).Take(field.Length);
                    if (field.Type.Equals("string", StringComparison.OrdinalIgnoreCase))
                    {
                        convertedFileData.AddRange(
                            Encoding.Convert(ebcdic, Encoding.ASCII, fieldSegment.ToArray())
                            );
                    }
                    else if (field.Type.Equals("B4", StringComparison.OrdinalIgnoreCase))
                    {
                        // Not sure how to convert this field
                    }
                    else if (field.Type.Equals("L8", StringComparison.OrdinalIgnoreCase))
                    {
                        // Not sure how to convert this field
                    }
                });
        }

        File.WriteAllBytes(convertedFilepath, convertedFileData.ToArray());
    }
}

【问题讨论】:

  • 您已经描述了您目前的情况,但没有提出任何问题:-)。我想您想说“如何从 IBM 5110 BASIC 编写的数据文件中转换 B4 和 L8 字段类型”......您需要向我们展示一些示例数据(十六进制转储),最好还有正确的解释。

标签: c# .net ascii ebcdic


【解决方案1】:

您必须首先知道固定记录大小。使用 FileStream.Read() 读取一条记录的字节。然后 Encoding.GetString() 将其转换为字符串。

然后使用 String.SubString() 从记录中找出字段。 B4 只是一个长度为 4 的 SubString 调用,L8 的长度为 8。进一步将此类字段转换为使用 Decimal.Parse() 的数字。您可能需要除以结果,不清楚使用什么定点乘数。 100 的赔率很高。

【讨论】:

  • 感谢您的反馈。我相信你所描述的就是我如何实现它。尽管我将每条记录作为字节数组处理。我将看看使用带有定点乘法器的 Decimal.Parse。这是个好建议。不幸的是,我只有记录布局和输出的文档,所以这是一种反复试验。
【解决方案2】:

好的,所以我想出了如何转换这两个字段。 B4 字段非常简单。它们本质上是一个可以转换为整数的 4 字节数组。

//The IBM 5110 were big endian machines, so reverse the array 
if (BitConverter.IsLittleEndian)
    Array.Reverse(by);

int value = BitConverter.ToInt32(by, 0);

L8 字段是代表IBM Double Precision Float 的 8 字节数组。有很多方法可以将其转换为IEEE 754 Float。可以在以下位置找到一些示例:

这是我根据文章指导使用的版本。

private double IbmFloatToDouble(byte[] value)
{
    if (ReferenceEquals(null, value))
        throw new ArgumentNullException("value");

    if (BitConverter.ToInt64(value, 0) == 0)
        return 0;

    int exponentBias = 64;
    int ibmBase = 16;
    double sign = 0.0D;

    int signValue = (value[0] & 0x80) >> 7;
    int exponentValue = (value[0] & 0x7f);
    double fraction1 = (value[1] << 16) + (value[2] << 8) + value[3];
    double fraction2 = (value[4] << 24) + (value[5] << 16) + (value[6] << 8) + value[7];
    double exponent24 = 16777216.0;             // 2^24
    double exponent56 = 72057594037927936.0;    // 2^56

    double mantissa1 = fraction1 / exponent24;
    double mantissa2 = fraction2 / exponent56;
    double mantissa = mantissa1 + mantissa2;
    double exponent = Math.Pow(ibmBase, exponentValue - exponentBias);

    if (signValue == 0) 
        sign = 1.0;
    else 
        sign = -1.0;

    return (sign * mantissa * exponent);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    相关资源
    最近更新 更多