Как я могу преобразовать вывод поля 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# может привести к округлению, поскольку двоичные числа с плавающей запятой не всегда могут точно представлять десятичные дроби.