簡體   English   中英

讀取 8 個字符的壓縮十進制 (Comp-3) 數值; 但持有 13 位數字並轉換為 13 位數值

[英]Read a packed decimal (Comp-3) number value which is 8 characters; but holds a 13 digit number and convert to 13 digits numeric value

我正在尋找代碼來讀取壓縮十進制 (Comp -3) 數值的文本文件,該數值是在主機系統中創建的,為 8 個字符,但包含壓縮十進制格式的 13 位數字。

我遇到了下面的代碼

private Decimal Unpack(byte[] inp, int scale)
{
    long lo = 0;
    long mid = 0;
    long hi = 0;
    bool isNegative;

    // this nybble stores only the sign, not a digit.  
    // "C" hex is positive, "D" hex is negative, and "F" hex is unsigned. 
    switch (nibble(inp, 0))
    {
        case 0x0D:
            isNegative = true;
            break;
        case 0x0F:
        case 0x0C:
            isNegative = false;
            break;
        default:
            throw new Exception("Bad sign nibble");
    }
    long intermediate;
    long carry;
    long digit;
    for (int j = inp.Length * 2 - 1; j > 0; j--)
    {
        // multiply by 10
        intermediate = lo * 10;
        lo = intermediate & 0xffffffff;
        carry = intermediate >> 32;
        intermediate = mid * 10 + carry;
        mid = intermediate & 0xffffffff;
        carry = intermediate >> 32;
        intermediate = hi * 10 + carry;
        hi = intermediate & 0xffffffff;
        carry = intermediate >> 32;
        // By limiting input length to 14, we ensure overflow will never occur

        digit = nibble(inp, j);
        if (digit > 9)
        {
            throw new Exception("Bad digit");
        }
        intermediate = lo + digit;
        lo = intermediate & 0xffffffff;
        carry = intermediate >> 32;
        if (carry > 0)
        {
            intermediate = mid + carry;
            mid = intermediate & 0xffffffff;
            carry = intermediate >> 32;
            if (carry > 0)
            {
                intermediate = hi + carry;
                hi = intermediate & 0xffffffff;
                carry = intermediate >> 32;
                // carry should never be non-zero. Back up with validation
            }
        }
    }
    return new Decimal((int)lo, (int)mid, (int)hi, isNegative, (byte)scale);
}

private int nibble(byte[] inp, int nibbleNo)
{
    int b = inp[inp.Length - 1 - nibbleNo / 2];
    return (nibbleNo % 2 == 0) ? (b & 0x0000000F) : (b >> 4);
}

但上面的代碼沒有說壞跡象蠶食。

誰能確認我是否正確閱讀

 using (FileStream fs = new FileStream(pathSource, FileMode.Open))
            {
                using (StreamReader reader = new StreamReader(fs))
                {
                    List<decimal> list = new List<decimal>();

                    while (!reader.EndOfStream)
                    {
                        byte[] b = ASCIIEncoding.ASCII.GetBytes(reader.ReadLine());
                        list.Add(Unpack(b, 0));
                    }

                    reader.Close();
                }
            }

注意:它不是重復的,因為我正在尋找可以讀取文件並將參數傳遞給 Unpack 方法的代碼。

作為參考,我添加了文件中的數據的樣子:

圖片

“ASCII 傳輸類型”會將文件作為常規文本文件傳輸。 因此,當我們以 ASCII 傳輸類型傳輸壓縮十進制或二進制數據文件時,文件會損壞。 “二進制傳輸類型”將以二進制模式傳輸數據,將文件作為二進制數據而不是文本數據處理。 因此,請為您的情況使用二進制傳輸類型。

參考: https://www.codeproject.com/Tips/673240/EBCDIC-to-ASCII-Converter

文件准備好后,這里是將壓縮十進制轉換為人類可讀十進制的代碼。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

   namespace ConsoleApp2
   {
    class Program
    {
        static void Main(string[] args)
        {
            var path = @"C:\FileName.BIN.dat";
            var templates = new List<Template>
            {
                new Template{StartPos=1,CharLength=4,Type="AlphaNum"},
                new Template{StartPos=5,CharLength=1,Type="AlphaNum"},
                new Template{StartPos=6,CharLength=8,Type="AlphaNum"},
                new Template{StartPos=14,CharLength=1,Type="AlphaNum"},
                new Template{StartPos=46,CharLength=4,Type="Packed",DecimalPlace=2},
                new Template{StartPos=54,CharLength=5,Type="Packed",DecimalPlace=0},
                new Template{StartPos=60,CharLength=4,Type="Packed",DecimalPlace=2},
                new Template{StartPos=64,CharLength=1,Type="AlphaNum"}
            };

            var allBytes = File.ReadAllBytes(path);
            for (int i = 0; i < allBytes.Length; i += 66)
            {
                var IsLastline = (allBytes.Length - i) < 66;
                var lineLength = IsLastline ? 64 : 66;
                byte[] lineBytes = new byte[lineLength];
                Array.Copy(allBytes, i, lineBytes, 0, lineLength);


                var outArray = new string[templates.Count];
                int index = 0;
                foreach (var temp in templates)
                {
                    byte[] amoutBytes = new byte[temp.CharLength];
                    Array.Copy(lineBytes, temp.StartPos - 1, amoutBytes, 0, 
    temp.CharLength);
                    var final = "";
                    if (temp.Type == "Packed")
                    {
                        final = Unpack(amoutBytes, temp.DecimalPlace).ToString();
                    }
                    else
                    {
                        final = ConvertEbcdicString(amoutBytes);
                    }

                    outArray[index] = final;
                    index++;

                }

                Console.WriteLine(string.Join(" ", outArray));

            }

            Console.ReadLine();
        }


        private static string ConvertEbcdicString(byte[] ebcdicBytes)
        {
            if (ebcdicBytes.All(p => p == 0x00 || p == 0xFF))
            {
                //Every byte is either 0x00 or 0xFF (fillers)
                return string.Empty;
            }

            Encoding ebcdicEnc = Encoding.GetEncoding("IBM037");
            string result = ebcdicEnc.GetString(ebcdicBytes); // convert EBCDIC Bytes -> 
    Unicode string
            return result;
        }

        private static Decimal Unpack(byte[] inp, int scale)
        {
            long lo = 0;
            long mid = 0;
            long hi = 0;
            bool isNegative;

            // this nybble stores only the sign, not a digit.  
            // "C" hex is positive, "D" hex is negative, AlphaNumd "F" hex is unsigned. 
            var ff = nibble(inp, 0);
            switch (ff)
            {
                case 0x0D:
                    isNegative = true;
                    break;
                case 0x0F:
                case 0x0C:
                    isNegative = false;
                    break;
                default:
                    throw new Exception("Bad sign nibble");
            }
            long intermediate;
            long carry;
            long digit;
            for (int j = inp.Length * 2 - 1; j > 0; j--)
            {
                // multiply by 10
                intermediate = lo * 10;
                lo = intermediate & 0xffffffff;
                carry = intermediate >> 32;
                intermediate = mid * 10 + carry;
                mid = intermediate & 0xffffffff;
                carry = intermediate >> 32;
                intermediate = hi * 10 + carry;
                hi = intermediate & 0xffffffff;
                carry = intermediate >> 32;
                // By limiting input length to 14, we ensure overflow will never occur

                digit = nibble(inp, j);
                if (digit > 9)
                {
                    throw new Exception("Bad digit");
                }
                intermediate = lo + digit;
                lo = intermediate & 0xffffffff;
                carry = intermediate >> 32;
                if (carry > 0)
                {
                    intermediate = mid + carry;
                    mid = intermediate & 0xffffffff;
                    carry = intermediate >> 32;
                    if (carry > 0)
                    {
                        intermediate = hi + carry;
                        hi = intermediate & 0xffffffff;
                        carry = intermediate >> 32;
                        // carry should never be non-zero. Back up with validation
                    }
                }
            }
            return new Decimal((int)lo, (int)mid, (int)hi, isNegative, (byte)scale);
        }

        private static int nibble(byte[] inp, int nibbleNo)
        {
            int b = inp[inp.Length - 1 - nibbleNo / 2];
            return (nibbleNo % 2 == 0) ? (b & 0x0000000F) : (b >> 4);
        }

        class Template
        {
            public string Name { get; set; }
            public string Type { get; set; }
            public int StartPos { get; set; }
            public int CharLength { get; set; }
            public int DecimalPlace { get; set; }
        }
    }
   }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM