Member 14097984 Ответов: 3

Обрабатывать оставшиеся байты при копировании в кратных 8x байтах?


Привет.
Я надеюсь, что кто-нибудь может указать мне правильное направление, пожалуйста.

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

Каждая строка в моей таблице данных имеет адрес смещения, а затем 8-кратные байтовые записи с метками 00, 01, 02 и т. д.

Мой пользовательский класс принимает байтовый ввод[] и циклически проходит через него, беря 8x байтов за раз и создавая "список" байтовых блоков моего пользовательского класса (это просто класс, который представляет блок из восьми байтов и смещения, так что я могу циклически проходить и добавлять их в сетку данных.

Теперь он работает нормально, при условии, что у меня есть структура byte[] кратная 8, однако, скажем, у меня есть byte[18] - теперь у меня есть 2x байтовые часы по 8 байт плюс 2x оставшихся байта.

Я пытаюсь понять, как создать третий блок данных с оставшимися более чем 2 байтами и заполнить оставшиеся 6 байтов 0x00, и вот здесь я застрял.

Я пробовал гуглить, но не уверен, что ищу, так что трудно найти решение.

Я постараюсь показать разделы кода, которые, по моему мнению, имеют отношение к делу, и я был бы очень благодарен, если бы кто-нибудь мог помочь, но, пожалуйста, примите во внимание, что я учусь и знаю, что мой код, скорее всего, будет грязным :)

<pre>private void BuildDataArray()
        {

            // TODO Need to re-write so that we can also create rows for odd number of byte left over, and set the rmaining bytes in that block to 0x00

            int dataSize = data.Length; // How many Bytes are in our full data block
            uint calcOffset = 0x00;

            int count = dataSize / 8; // Get a count of each 8 byte block
            int bytesToTake = 8;
            int bytesToSkip = 0;

            for (int i = 0; i < count; i++)
            {


                byte[] tempData = data.Skip(bytesToSkip).Take(bytesToTake).ToArray();

                bytesToSkip = bytesToSkip + 8;
                bytesToTake = bytesToTake + 8;

                ByteBlock tempByteBlock = new ByteBlock(tempData, calcOffset);

                calcOffset = calcOffset + 8;

                _byteBlock.Add(tempByteBlock); // Add each 8 byte block to the main ByteBlockArray

            }


        }



Это мой класс ByteBlockArray, который содержит массив байтовых часов, которые, в свою очередь, содержат 8 байтовых блоков данных со смещением...

<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataTest
{
    class ByteBlockArray
    {
        private List<ByteBlock> _byteBlock = new List<ByteBlock>(); // Array/List of ByteBlock objects each to hold an 8 byte "recoord" for the datagrid


        private byte[] data; // This is the full data block that will be used to create 8xbyte blocks
        private byte offset; // This will hold the initial offset for the full data block



        public ByteBlockArray(byte[] data, byte offset)
        {
            this.data = data;
            this.offset = offset;


            BuildDataArray();

        }



        private void BuildDataArray()
        {

            // TODO Need to re-write so that we can also create rows for odd number of byte left over, and set the rmaining bytes in that block to 0x00

            int dataSize = data.Length; // How many Bytes are in our full data block
            uint calcOffset = 0x00;

            int count = dataSize / 8; // Get a count of each 8 byte block
            int bytesToTake = 8;
            int bytesToSkip = 0;

            for (int i = 0; i < count; i++)
            {


                byte[] tempData = data.Skip(bytesToSkip).Take(bytesToTake).ToArray();

                bytesToSkip = bytesToSkip + 8;
                bytesToTake = bytesToTake + 8;

                ByteBlock tempByteBlock = new ByteBlock(tempData, calcOffset);

                calcOffset = calcOffset + 8;

                _byteBlock.Add(tempByteBlock); // Add each 8 byte block to the main ByteBlockArray

            }


        }



        public ByteBlock GetByteBlockIndex(int index)
        {
            return _byteBlock[index];
        }

        public int GetByteBlockCount()
        {
            return this._byteBlock.Count;
        }
    }
}


Это класс байтовых блоков, как описано выше, и это "список" элементов, отображаемых в моей таблице данных...

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

namespace DataTest
{
    class ByteBlock
    {
        
        private byte _00 = 0x00;
        private byte _01 = 0x00;
        private byte _02 = 0x00;
        private byte _03 = 0x00;
        private byte _04 = 0x00;
        private byte _05 = 0x00;
        private byte _06 = 0x00;
        private byte _07 = 0x00;
        private byte[] tempData;
        private uint calcOffset;

        public ByteBlock(byte[] tempData, uint calcOffset)
        {
            this.tempData = tempData;
            this.calcOffset = calcOffset;

            FillBytes();

        }

        public ByteBlock()
        {
        }

        private void FillBytes()
        {
            this._00 = tempData[0];
            this._01 = tempData[1];
            this._02 = tempData[2];
            this._03 = tempData[3];
            this._04 = tempData[4];
            this._05 = tempData[5];
            this._06 = tempData[6];
            this._07 = tempData[7];
        }




        public uint Offset
        {
            get { return calcOffset; }
        }

        public byte i00
        {
            get { return _00; }
        }

        public byte i01
        {
            get { return _01; }
        }

        public byte i02
        {
            get { return _02; }
        }

        public byte i03
        {
            get { return _03; }
        }

        public byte i04
        {
            get { return _04; }
        }

        public byte i05
        {
            get { return _05; }
        }

        public byte i06
        {
            get { return _06; }
        }

        public byte i07
        {
            get { return _07; }
        }

    }
}


И это код, который я использую в основной форме для тестирования, передавая в фиктивный массив байтов. Если массив байтов кратен 8 байтам, он работает нормально, если нет, то он не будет работать так, как есть...

<pre>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DataTest
{
    public partial class Form1 : DevExpress.XtraEditors.XtraForm
    {

        List<ByteBlock> dataStructure = new List<ByteBlock>();

        public Form1()
        {
            InitializeComponent();
        }



        private void ButtonCreateData_Click(object sender, EventArgs e)
        {

            byte[] data = {0xed, 0xc6, 0x43, 0x32, 0x45, 0xd3, 0x3a, 0x43, 0xed, 0xc6, 0x43, 0x32, 0x45, 0xd3, 0x3a, 0x43};

            ByteBlockArray byteArray = new ByteBlockArray(data, 0x00);



            // CAUTION! TEMP area to load data to grid, need to move this to correct place and change as required


            int count = byteArray.GetByteBlockCount();
            ByteBlock bblock = new ByteBlock();


            for (int i = 0; i < count; i++)
            {
                bblock = byteArray.GetByteBlockIndex(i);

                // Now add data/rows to grid
                // outputTokenView.Items.Add(new ListViewItem(new string[] { tkn.GetSerialAsString(), tkn.GetSeedAsString(), tkn.GetKeyAsString(), tkn.GetCreationDate(), tkn.GetExpiryDaysAsString(), tkn.GetStateAsString(), tkn.GetSignatureAsString() }));

                dataStructure.Add(bblock);
                
            }

            gridControl1.DataSource = dataStructure;

        }


    }
}


Кроме того, просто чтобы отметить, что я использую элемент управления сеткой данных из подписки DevExpress Winforms.

Еще раз большое вам спасибо за любую помощь...

Что я уже пробовал:

Я узнал все, что было так далеко от моих учебных книг и Google, но не смог узнать, как пройти этот момент, так как даже не уверен, что я ищу.

Спасибо

3 Ответов

Рейтинг:
18

Richard MacCutchan

Логика довольно проста:

byteArray = // input data
numberOfBytes = // length of input data
blockSize = 8
offset = 0
WHILE numberOfBytes > 0
DO
    copybytes(byteArray[offset], destinationAddress, blocksize) // copy a block
    offset += blockSize                                         // increment the offset
    numberOfBytes -= blockSize                                  // decrement the number remaining
    if numberOfBytes < blockSize    // if remainder is less than the blocksize
        blockSize = numpberOfBytes  // set the blocksize to remainder for last block
DONE


Member 14097984

Спасибо за ответы, однако логика, показанная выше, была именно тем, что мне нужно, спасибо.

Могу ли я просто спросить, считаете ли вы, что моя установка на то, чего я пытаюсь достичь, кажется нормальной, или это немного слишком сложно (попытка обойти объектно-ориентированный путь).

Моя классовая структура в основном такова.

1. класс Byte - содержит байт, его адрес и свойства (например, это защищенный байт)
2. класс байтового блока - он содержит 8 байт из вышеперечисленных, а также адрес смещения
3. класс ByteBlockArray - массив объектов байтового блока, с методами создания каждого 8-байтового блока из необработанных данных[]
4. ByteDataClass - это просто пользовательский класс с открытым get/set для каждого компонента в классе байтовых блоков, используемый для привязки к моей таблице данных и отображения данных.

Идя с вышеприведенным дизайном, все, кажется, работает нормально, однако я не могу не чувствовать, что он может быть чрезмерно дополнен для своей предполагаемой цели, которая в конечном счете состоит в том, чтобы взять байт[] любой длины и отобразить строки по 8 байт и смещение на сетке данных, точно так же, как стандартный шестнадцатеричный дисплей.

В любом случае, еще раз спасибо! :)
Стивен

Richard MacCutchan

Я бы предположил, что это немного слишком сложно. Я бы использовал один класс, который может быть инициализирован блоком (т. е. массивом) байтов, а затем может возвращать его в блоках по 8 байт. Я не уверен, что вы подразумеваете под защищенным байтом или как вы его распознаете.

Member 14097984

Привет, Ричард, спасибо.

Защищенный байт-это тот, который был защищен (сделан только для чтения) на моей смарт-карте памяти, поэтому, имея свойство, которое помечает байт как защищенный, я могу отображать байт в другом цвете в моей сетке данных.

Если бы я пошел только с одним классом, как вы предложили, должен ли я все еще создавать свой класс для хранения информации, отображаемой в моей сетке данных, так как для этого нужен класс "список" для привязки в качестве источника данных, а затем я мог бы установить его свойства из моего основного класса блоков данных, или вы рекомендуете построить его в один класс и иметь этот источник 8 байт и отправлять данные для сетки?

Спасибо снова.
Стивен

Richard MacCutchan

Если некоторые байты защищены, то вам нужен какой-то способ идентифицировать это свойство, которое может быть дополнительным классом.
Класс, содержащий данные, должен предоставить методы, позволяющие привязать его к datagrid. Документация на MSDN объясняет, как это сделать.

Member 14097984

И еще одна последняя вещь, если я соглашусь с вашим предложением, как бы я заставил класс возвращать блоки по 8 байт для моей сетки данных. Например, если у меня есть один класс, который я передаю в данных[16], и это "список", привязанный к моей сетке данных, как бы я заставил этот класс вернуть 2 блока по 8 байт для сетки? Надеюсь, что это имеет смысл, извините, все еще учусь :) еще раз спасибо, Стивен.

Richard MacCutchan

Сначала вам нужно создать класс данных и привязать его к datagrid, как я уже упоминал выше.

Member 14097984

Sorry I don't think I explained myself correctly. The data grid I am using is from DevExpress, not Microsoft, and it requires a <list> object, so what I would like to know is should I create a custom class for the data, and one that performs the 8 byte operations, or should I simply put it all in the one class, and use this class as the data source as well. Lastly, if I need a <list> of objects for my Data Grid, then I can't see how my class could return multiple 8 byte objects/rows, and this was the reason I had created a third class which was a Byte Block Array, that performed these operations and returned individual 8 byte block items, however, that is when it got complecated:)

Спасибо снова
Стивен

Richard MacCutchan

Ладно, это вроде как упрощает дело. Создайте свой объект списка, используя код, который я предложил выше. Возможно, вам придется настроить его так, чтобы любой конечный блок действительно содержал 8 байт (добавив ноль байтов в конце).

Member 14097984

Спасибо за помощь и счастливого Рождества.
Спасибо
Стивен

Richard MacCutchan

Буду рад помочь. Счастливого Рождества и вам.

Member 14097984

Спасибо, Ричард. Пожалуйста, прости меня за то, что я вернулся еще раз, я все еще застрял :(

Я последовал вашему совету и создал всего один класс, и в этом классе я использовал ваш код, и он работает и правильно копирует байты независимо от размера массива, однако у меня есть 2 проблемы с человеком, которые я до сих пор не знаю, как решить.

1. Как я могу установить его так, чтобы я возвращал 8x byes за блок. Поэтому, если, например, я передам 10 байт, у меня будет 1 полный 8-байтовый блок, а затем я создам следующий 8-байтовый блок с последними 2 байтами и заполню оставшиеся 6 как 0x00.

2. я не могу понять, как этот класс может возвращать отдельные объекты для моего "списка" в основной форме, чтобы я мог отображать их в своей таблице данных.

Нужно ли мне будет создать "список" объектов моего класса блоков внутри фактического класса блоков и вернуть их?

Я добавил свой код ниже, который теперь находится все в одном классе.

Опять же, я очень признателен, если вы сможете помочь :)

<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataTest
{
    class ByteBlock
    {
        // 8 Bytes and Offset for Byte Block
        private byte _00 = 0x00;
        private byte _01 = 0x00;
        private byte _02 = 0x00;
        private byte _03 = 0x00;
        private byte _04 = 0x00;
        private byte _05 = 0x00;
        private byte _06 = 0x00;
        private byte _07 = 0x00;
        private int _offset;

        private List<ByteBlock> list = new List<ByteBlock>(); // List of ByteBlocks to return for List/Data Grid




        public ByteBlock(byte[] data, int offset)
        {
            // Loop throught the provided data and build List of ByteBlocks with 8x Bytes and calculated offset's
            // Set each byte value and the offset, then add the object to the List

            byte[] _byteArray = data;
            int _numberOfBytes = data.Count();
            int _blockSize = 8;
            int _offset = offset;

            byte[] tmpDat = new byte[_numberOfBytes];


            do
            {

                Buffer.BlockCopy(_byteArray, _offset, tmpDat, _offset, _blockSize); // copy a block

                _offset += _blockSize;                                         // increment the offset
                _numberOfBytes -= _blockSize;                                  // decrement the number remaining

                if (_numberOfBytes < _blockSize)    // if remainder is less than the blocksize
                    _blockSize = _numberOfBytes;  // set the blocksize to remainder for last block
            } while (_numberOfBytes > 0);



        }






        


        // Public Interface methods for data grid
        public int Offset
        {
            get { return _offset; }
        }

        public byte i00
        {
            get { return _00; }
        }

        public byte i01
        {
            get { return _01; }
        }

        public byte i02
        {
            get { return _02; }
        }

        public byte i03
        {
            get { return _03; }
        }

        public byte i04
        {
            get { return _04; }
        }

        public byte i05
        {
            get { return _05; }
        }

        public byte i06
        {
            get { return _06; }
        }

        public byte i07
        {
            get { return _07; }
        }


    }
}


В моем основном классе мне нужно как-то передать байт[] и получить обратно отдельные (список/массив?) объекты размером 8x байт, чтобы каждый 8-байтовый блок стал строкой в моей сетке данных.

Еще раз благодарю вас за то, что вы можете мне помочь.
С уважением
Стивен

Richard MacCutchan

Смотрите мое второе решение ниже.

Рейтинг:
0

Gerry Schmitz

Базовая логика ввода-вывода использует "буферы", которые могут содержать максимальное количество считанных / записанных "данных".

Просто возьмите ваши "переменные" данные и загрузите их в "буфер", который является некоторым кратным 8, а затем разрежьте его на куски. Очевидно, вам нужно отслеживать длину "фактических" данных в буфере.


Рейтинг:
0

Richard MacCutchan

Создайте класс, который может возвращать данные по 8 байт за раз, реализовав IEnumerable интерфейс, что-то вроде:

using System;
using System.Collections;


public class Bytes : IEnumerable
{
    private Byte[] _bytes;
    // create the internal byte block from the array passed in
    public Bytes(Byte[] pArray)
    {
        _bytes = new Byte[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _bytes[i] = pArray[i];
        }
    }

    // Implementation for the GetEnumerator method.
    IEnumerator IEnumerable.GetEnumerator()
    {
        return (IEnumerator)GetEnumerator();
    }

    public ByteEnum GetEnumerator()
    {
        return new ByteEnum(_bytes);
    }
}

// When you implement IEnumerable, you must also implement IEnumerator.
public class ByteEnum : IEnumerator
{
    public Byte[] _bytes;

    // Enumerators are positioned before the first element
    // in this case an element is an 8-byte block
    // until the first MoveNext() call.
    int offset = -8;
    int remainder = 0;  // number of bytes remining to be copied

    // create a new enumerator
    public ByteEnum(Byte[] list)
    {
        _bytes = list;
        remainder = _bytes.Length;
    }

    // move to the next 8-byte block
    public bool MoveNext()
    {
        offset += 8;
        // this returns true if more data, false if not
        // and controls the action of the foreach statement
        return (remainder > 0);
    }

    // restart at the beginning of the data
    public void Reset()
    {
        offset = -8;
        remainder = _bytes.Length;
    }

    // returns the current 8-byte block
    object IEnumerator.Current
    {
        get
        {
            return Current;
        }
    }

    public Byte[] Current
    {
        get
        {
            try
            {
                // allocate a new 8-byte block and copy the next
                // group of 8-bytes from the source
                Byte[] newbytes = new byte[8];
                int count = remainder > 8 ? 8 : remainder;
                Array.Copy(_bytes, offset, newbytes, 0, count);
                // reduce the number still to copy
                remainder -= 8;
                return newbytes;
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}


class App
{
    static void Main()
    {
        Bytes data = new Bytes(new byte[] { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 });
        foreach (Byte[] ba in data)
            Console.WriteLine(String.Format("{0} {1} {2} {3} {4} {5} {6} {7} ", (char)ba[0], (char)ba[1], (char)ba[2], (char)ba[3], (char)ba[4], (char)ba[5], (char)ba[6], (char)ba[7]));
        Console.ReadLine();
    }
}

Обратите внимание, что вам может потребоваться настроить ByteEnum.Current() метод для возврата байтов в виде печатаемых символов.


Member 14097984

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

Спасибо
Стивен

Richard MacCutchan

Рад помочь, желаю удачи.