Как я могу преобразовать вывод поля Cobol COMP в читаемый десятичный в C#?

При преобразовании программы на Cobol в C# я столкнулся с COMP:

03  Var1                     PIC X(4).
03  Var2                     PIC X(3).
03  Var3                     PIC X(3).
03  Var4                     PIC X(4).
03  Var5                     PIC X(16).
03  Var6                     PIC X(4).
03  Var7                     PIC X(2).
03  Var8                     PIC X.
03  Var9                     PIC X(4).
03  Var10                    PIC X(16).
03  Var11                    PIC S9(7)V9(2) COMP.
03  Var12                    PIC S9(7)V9(2) COMP.
03  Var13                    PIC S9(7)V9(2) COMP.
03  Var14                    PIC S9(7)V9(2) COMP.
03  Var15                    PIC S9(7)V9(2) COMP.
03  Var16                    PIC S9(7)V9(2) COMP.
03  Var17                    PIC S9(7)V9(2) COMP.
03  Var18                    PIC S9(7)V9(2) COMP.
03  Var19                    PIC S9(7)V9(2) COMP.
03  Var20                    PIC S9(7)V9(2) COMP.
03  Var21                    PIC S9(7)V9(2) COMP.
03  Var22                    PIC S9(7)V9(2) COMP.
03  Var23                    PIC S9(7)V9(2) COMP.
03  Var24                    PIC S9(7)V9(2) COMP.

Я провел несколько часов, изучая COMP. Большинство поисков дают что-то про COMP-3 или упоминают, что COMP - это двоичное преобразование. Тем не менее, выходные данные COMP программы cobol - это поля не-COMP, за которыми следуют (в скобках):

( F ” " )

в то время как фактические значения равны 0,00, за исключением того, что var13 равен 64,70

ПРИМЕЧАНИЕ: это значения, скопированные из Notepad++. Также обратите внимание, что я очень мало знаю о коболе.

Как я могу преобразовать из COMP в десятичную? В идеале, я мог бы также преобразовать десятичную в COMP, так как мне нужно вернуть все в тот же формат.

Я пытался читать данные в двоичном виде с:

public static void ReadBinaryFile(string directoryString)
    {
        using (BinaryReader reader = new BinaryReader(File.Open(directoryString, FileMode.Open)))
        {
            string myString = Encoding.ASCII.GetString(reader.ReadBytes(113));
            Console.WriteLine(myString);
        }
    }

РЕДАКТИРОВАТЬ: на правильном пути

Спасибо @piet.t и @jdweng за помощь.

Хотя с этим тестовым кодом все еще существует проблема, это должно помочь любому, кто находится на моей позиции, с их решением:

public static void ReadBinaryFile(string directoryString)
    {
        using (BinaryReader reader = new BinaryReader(File.Open(directoryString, FileMode.Open)))
        {
            string asciiPortion = Encoding.ASCII.GetString(reader.ReadBytes(57)); // Read the non-comp values

            Console.Write(asciiPortion); // Test the ascii portion 

            Console.WriteLine("var11: " + reader.ReadInt32());
            Console.WriteLine("var12: " + reader.ReadInt32());
            Console.WriteLine("var13: " + reader.ReadInt32());
            Console.WriteLine("var14: " + reader.ReadInt32());
            Console.WriteLine("var15: " + reader.ReadInt32());
            Console.WriteLine("var16: " + reader.ReadInt32());
            Console.WriteLine("var17: " + reader.ReadInt32());
            Console.WriteLine("var18: " + reader.ReadInt32());
            Console.WriteLine("var19: " + reader.ReadInt32());
            Console.WriteLine("var20: " + reader.ReadInt32());
            Console.WriteLine("var21: " + reader.ReadInt32());
            Console.WriteLine("var22: " + reader.ReadInt32());
            Console.WriteLine("var23: " + reader.ReadInt32());
            Console.WriteLine("var24: " + reader.ReadInt32());
        }
    }

РЕДАКТИРОВАТЬ 2: пытаясь найти проблему

Проблема: после каждого значения следует какое-то мусорное значение, которое печатается как следующий int32.

Фактические значения:

var11 = var12 = 0.00
var13 = 58.90
var14 = 0.00
var15 = -0.14
var16 = 0.00
var17 = var18 = var19 = var20 = 0.00
var21 = var22 = var23 = var24 = 0.00

Выход (с отступом):

Var11:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var12:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var13:  5890  HEX: 00001702  BIN: 00000000000000000001011100000010
Var14:   368  HEX: 00000170  BIN: 00000000000000000000000101110000
Var15:   -14  HEX: FFFFFFF2  BIN: 11111111111111111111111111110010
Var16:    -1  HEX: FFFFFFFF  BIN: 11111111111111111111111111111111
Var17:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var18:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var19:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var20:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var21:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var22:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var23:     0  HEX: 00000000  BIN: 00000000000000000000000000000000
Var24:     0  HEX: 00000000  BIN: 00000000000000000000000000000000

Блокнот ++ (Скопировано) Представление:

          p  òÿÿÿÿÿÿÿ                                

Notepad ++ (Visual) Представление:

[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][STX][ETB][NUL][NUL]p[SOH]
[NUL][NUL]òÿÿÿÿÿÿÿ[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL]
[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL]
[NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][NUL][LF]

РЕДАКТИРОВАТЬ 3: Решение!

У @piet.t все было в порядке. Спасибо за полезный ответ на мой первый вопрос! Эта проблема была специфической для программы cobol. Я был убежден, что Var14 всегда был 0, но:

Var14 = SomeCalculationIHadNoIdeaAbout(Var13, SomeOtherNumber);

Я использовал RecordEdit для более легкой настройки данных (Внимание: программа немного странная в некоторых местах) и заметил странную тенденцию в значениях "мусора".

Реальным решением моей проблемы является код в первом редактировании, который я сделал несколько дней назад:/.

ПРИМЕЧАНИЕ: мне также пришлось использовать символ перевода строки, который я не вставил в этот код. Для этого просто добавьте еще один reader.ReadBytes(1);,

ПРИМЕЧАНИЕ 2: Вам может понадобиться изучить EBDCDIC и / или Endianness, что может сделать ваше решение немного сложнее, чем мое.

1 ответ

Решение

Здесь все будет немного сложнее, поскольку в COBOL-программе используются переменные с фиксированной запятой, которых, я думаю, C# не знает.

Для обращения обращайтесь с каждым PIC S9(7)V9(2) COMPполе как Int32 (это должен быть формат BigEndian). Но обратите внимание, что вы не получите реальное значение, но value*100 из-за неявной десятичной точки в объявлении поля COBOL.

Обратите внимание, что использование данных с фиксированной точкой позволит проводить точные вычисления для значений с десятичными знаками, а преобразование их в плавающую точку в C# может привести к округлению, поскольку двоичные числа с плавающей запятой не всегда могут точно представлять десятичные дроби.

Другие вопросы по тегам