Распаковка десятичных дробей, упакованных в формате EBCDIC (COMP-3), в преобразовании ASCII
Вопрос
Я использую Реализация EBCDIC Джона Скита в .NET для чтения файла VSAM, загруженного в двоичном режиме по FTP из системы мэйнфреймов.Он очень хорошо работает для чтения / записи в этой кодировке, но в нем нет ничего для чтения упакованных десятичных значений.Они содержатся в моем файле, и мне нужно их распаковать (очевидно, ценой большего количества байт).
Как я могу это сделать?
Мои поля определяются как PIC S9(7)V99 COMP-3.
Решение
Ах, BCD.Посигналите, если вы использовали его в сборке 6502.
Конечно, лучше всего позволить COBOL MOVE сделать эту работу за вас!Одна из этих возможностей может помочь.
(Возможность № 1) Предполагая, что у вас есть доступ к мэйнфрейму и исходному коду, а выходной файл предназначен ТОЛЬКО для вашего использования, измените программу так, чтобы она просто перемещала значение в обычный распакованный PIC S9 (7) V99.
(Возможность № 2) Предполагая, что это не так просто (например, файл является входным для других pgm или не может изменить код), вы можете написать другую программу на COBOL в системе, которая считывает этот файл и записывает другой.Вырежьте и вставьте макет записи файла с помощью BCD в новую программу для ввода и вывода файлов.Измените выходную версию, чтобы она была неупакованной.Прочитайте запись, выполните "соответствующее перемещение" для передачи данных и записывайте до eof.Затем перенесите это файл.
(Возможность № 3) Если вы не можете прикоснуться к мэйнфрейму, обратите внимание на описание в статье, на которую вы дали ссылку в своем комментарии.BCD относительно прост.IT мог бы будь таким же простым, как это (vb.net):
Private Function FromBCD(ByVal BCD As String, ByVal intsz As Integer, ByVal decsz As Integer) As Decimal
Dim PicLen As Integer = intsz + decsz
Dim result As Decimal = 0
Dim val As Integer = Asc(Mid(BCD, 1, 1))
Do While PicLen > 0
result *= 10D
result += val \ 16
PicLen -= 1
If PicLen > 0 Then
result *= 10D
result += val Mod 16
PicLen -= 1
BCD = Mid(BCD, 2)
End If
val = Asc(Mid(BCD, 1, 1))
Loop
If val Mod 16 = &HD& Then
result = -result
End If
Return result / CDec(10 ^ decsz)
End Function
Я протестировал это с несколькими вариантами этого вызова:
MsgBox(FromBCD("@" & Chr(13 + 16), 2, 1))
Например, равно -40.1.Но только некоторые.Так что это все еще может быть неправильно.
Итак, если ваш comp-3 запускается, скажем, с 10 байта макета входной записи, это решило бы проблему:
dim valu as Decimal = FromBCD(Mid(InputLine,10,5), 7,2))
Отмечая формулы из статьи о преобразовании данных для количества байтов для отправки и количества 9-х до и после V.
Сохраните результат в десятичном формате, чтобы избежать ошибок округления.Особенно, если это $ $$.Float & Double причинит вам огорчение!Если вы не обрабатываете его, даже строка будет лучше.
конечно , это мог бы будь тверже.Там, где я работаю, мэйнфрейм равен 9 битам на байт.Серьезный.Это то, что делает первые 2 возможности такими заметными.Конечно, что действительно делает их лучше, так это тот факт, что вы можете быть программистом только для ПК, и это отличный повод нанять программиста для мэйнфреймов, который сделает эту работу за вас!Если вам так повезло, что у вас есть такая возможность...
Мира, -Ал