3

ファイルをECDICからASCII形式に変換しようとしていますが、興味深い問題が発生しました。ファイルには、固定長のレコードが含まれ、一部のフィールドは符号付き2進整数(レコードレイアウトではB4と記述)、および長精度の数値(レコードレイアウトではL8と記述)です。文字データは問題なく変換できましたが、どうすれば変換できるのかわかりません。元のシステム( IBM 5110 )のリファレンス・マニュアルから、フィールドを以下に説明します。

Bは、BASIC内部データ形式に変換される固定小数点符号付き2進整数形式の数値データ項目の長さ(2、4、または8バイト)を示します。レコードI/Oファイル入力の場合、レコードの次の2、4、または8バイトには、システムによって内部データ形式に変換され、READFILEまたはREREADで指定された変数に割り当てられる符号付きバイナリ値が含まれます。 FORMステートメントを使用したFILEステートメント。

Lは、数値の長精度(8文字)を示します。入力の場合、このエントリは、レコード内の8桁の長精度値が、READFILEまたはREREADFILEステートメントで指定された対応する数値変数に変換されずに割り当てられることを示します。

編集:これが私が変換に使用しているコードです

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());
    }
}
4

2 に答える 2

2

まず、固定レコードサイズを知っておく必要があります。FileStream.Read()を使用して、1レコード分のバイトを読み取ります。次に、Encoding.GetString()を使用して文字列に変換します。

次に、String.SubString()を使用して、レコードからフィールドをフィッシングします。B4は、長さが4のSubString呼び出しであり、長さが8のL8です。さらに、このようなフィールドをDecimal.Parse()を使用して数値に変換します。結果を除算する必要があるかもしれませんが、どの固定小数点乗数が使用されているかが明確ではありませんでした。100の良いオッズ。

于 2013-01-09T15:02:20.070 に答える
1

さて、私は両方のフィールドを変換する方法を理解しました。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倍精度浮動小数点数を表す8バイト配列です。これをIEEE754Floatに変換する方法はたくさんあります。いくつかの例は次の場所にあります。

これが、記事のガイダンスに基づいて使用したバージョンです。

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);
}
于 2013-03-02T05:14:44.993 に答える