Я пытаюсь импортировать EDI-файл мейнфрейма обратно в SQL Server с помощью .NET, и у меня возникают проблемы с распаковкой некоторых полей comp-3.
Этот файл был от одного из наших клиентов, и у меня есть макет книги для копирования для следующих полей:
05 EH-GROSS-INVOICE-AMT PIC S9(07)V9999 COMP-3.
05 EH-CASH-DISCOUNT-AMT PIC S9(07)V9999 COMP-3.
05 EH-CASH-DISCOUNT-PCT PIC S9(03)V9999 COMP-3.
Я просто сосредоточусь на этих трех полях, поскольку все остальные поля являются PIC (X) и уже являются значениями Unicode. Я загрузил все с помощью этого инструмента Ebcdic2Ascii, который был создан Максом Вагнером. Я только что немного модифицировал функцию распаковки и изменил ее на
private string Unpack(byte[] packedBytes, int decimalPlaces, out bool isParsedSuccessfully)
{
isParsedSuccessfully = true;
return BitConverter.ToString(packedBytes);
}
чтобы я мог получить следующие образцы данных:
EH-GROSS-INVOICE-AMT EH-CASH-DISCOUNT-AMT EH-CASH-DISCOUNT-PCT
----------------------------------------------------------------------
00-1A-1A-03-26-0C 00-00-00-00-00-0C 00-00-00-0C
00-0A-1A-1A-00-0C 00-00-1A-1A-2D-0C 00-1A-00-0C
00-09-10-20-00-0C 00-00-10-1A-1A-0C 00-1A-00-0C
Вот пример кода, который я создал для распаковки этих значений, основываясь на моем понимании значений Comp-3:
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var result1 = UnpackMod("00-1A-1A-03-26-0C", 4);
var result2 = UnpackMod("00-00-00-00-00-0C", 4);
var result3 = UnpackMod("00-00-00-0C", 4);
Console.WriteLine($"{result1}\n{result2}\n{result3}\n");
var result4 = UnpackMod("00-0A-1A-1A-00-0C", 4);
var result5 = UnpackMod("00-00-1A-1A-2D-0C", 4);
var result6 = UnpackMod("00-1A-00-0C", 4);
Console.WriteLine($"{result4}\n{result5}\n{result6}\n");
var result7 = UnpackMod("00-09-10-20-00-0C", 4);
var result8 = UnpackMod("00-00-10-1A-1A-0C", 4);
var result9 = UnpackMod("00-1A-00-0C", 4);
Console.WriteLine($"{result7}\n{result8}\n{result9}");
Console.ReadLine();
}
/// <summary>
/// Method for unpacking Comp-3 fields.
/// </summary>
/// <param name="hexString"></param>
/// <param name="decimalPlaces"></param>
/// <returns>Returns numeric string if parse was successful; else Return input hex string</returns>
private static string UnpackMod(string inputString, int decimalPlaces)
{
var outputString = inputString;
// Remove "-".
outputString = outputString.Replace("-", "");
// Check last character for sign.
string lastChar = outputString.Substring(outputString.Length - 1, 1);
bool isNegative = (lastChar == "D" || lastChar == "B");
// Remove sign character.
if (lastChar == "C" || lastChar == "A" || lastChar == "E" || lastChar == "F" || lastChar == "D" || lastChar == "B")
{
outputString = outputString.Substring(0, outputString.Length - 1);
}
// Place decimal point.
outputString = outputString.Insert(outputString.Length - decimalPlaces, ".");
// Check if parsed value is numeric. This will also eliminate all leading 0.
var isParsedSuccessfully = decimal.TryParse(outputString, out decimal decimalValue);
// If isParsedSuccessfully is true then return numeric string else return inputString..
string result = "NULL";
if (isParsedSuccessfully)
{
// Convert value to negative.
if (isNegative)
{
decimalValue = decimalValue * -1;
}
result = decimalValue.ToString();
}
return result;
}
}
}
После запуска примера кода я смог получить следующие результаты:
EH-GROSS-INVOICE-AMT EH-CASH-DISCOUNT-AMT EH-CASH-DISCOUNT-PCT
----------------------------------------------------------------------
NULL 0.0000 0.0000
NULL NULL NULL
9102.0000 NULL NULL
Как видите, я смог правильно получить только следующие 3 значения:
00-09-10-20-00-0C -> 9102.0000
00-00-00-00-00-0C -> 0.0000
00-00-00-0C -> 0.0000
Согласно ссылке из этого источника: http://www.3480-3590-data-conversion.com/article-packed-fields.html. У меня есть следующее понимание Comp-3:
COBOL Comp-3 — это двоичный тип поля, который помещает (упаковывает) две цифры в каждый байт, используя нотацию, называемую двоично-десятичным кодированием или BCD.
Тип данных Binary Coded Decimal (BCD) полностью соответствует своему названию — это значение, хранящееся в десятичной системе счисления (с основанием десять), и каждая цифра закодирована в двоичном формате. Так как цифра имеет только десять возможных значений (0-9).
Младший полубайт младшего значащего байта используется для хранения знака числа. Этот полубайт хранит только знак, а не цифру. C hex положительный, D hex отрицательный, а F hex беззнаковый.
Поскольку я знаю, что BCD должны быть только значения 0-9 и что в конце должен быть только символ, который может быть C, D или F. Я не знаю, как распаковать следующие значения:
00-1A-1A-03-26-0C
00-0A-1A-1A-00-0C
00-00-1A-1A-2D-0C
00-1A-00-0C
00-00-10-1A-1A-0C
00-1A-00-0C
Эти значения имеют другие символы помимо символа знака. У меня такое ощущение, что данные уже были преобразованы, потому что если это не так, то там не должно быть читаемых значений, если только вы не примените кодировку. Я все еще не уверен в этом и хотел бы получить любую информацию по этому поводу. Спасибо.
scp
, для вас будет сделано преобразование. FTPS как Binary лучше, или существующее решение может что-то делать. В z/OS вы можете просмотреть файл в ISPF, а затем ввестиhex
в командной строке, чтобы просмотреть шестнадцатеричные значения данных и сделать снимок экрана. - person Hogstrom   schedule 04.01.2021