2

I have a binary file that I want to read. Let's say its "foo.bin". I want to read all the bytes into an byte array.
byte[] data = File.ReadAllBytes("foo.bin")
I want to split these bytes into binary numbers of length x.
(Using a custom class BinaryChunk, but any type of binary / bool[] / byte[] will work fine.)

struct BinaryChunk { 
    bool[] data,
    int size
} 

BinaryChunk[] binaryChunks = SplitDataIntoBinaryChunksOfSize(data, x)

*Note that "x" is in bits, not bytes.

Examples in case you still have no idea what I'm talking about:
(Shortened "SplitDataIntoBinaryChunksOfSize" into "SplitData" for obvious reasons)

bool[] foo = new bool[]{0b11100110, 0b00010110};
SplitData(foo, 3) //-> 111, 001, 100, 001, 011, 000
//   1 1 1 0 0 1 1 0;0 0 0 1 0 1 1 0XXXXXXXXXXXXXXXX
//-> 1 1 1;0 0 1;1 0 0;0 0 1;0 1 1;0 0 0
SplitData(foo, 12) //-> 111001100001, 011000000000
//   1 1 1 0 0 1 1 0;0 0 0 1 0 1 1 0XXXXXXXXXXXXXXXX
//-> 1 1 1 0 0 1 1 0 0 0 0 1;0 1 1 0 0 0 0 0 0 0 0 0

Thinking about using BitArray, but I haven't used it enough to know how to use it. Anyone got any ideas?

EDIT: heres a quick solution if anyone needs one i guess

class BinaryStream {
            //binary data in bytes
            byte[] data;
            //length of data
            int size;

            public BinaryStream(byte[] data) {
                this.data = data;
                this.size = data.Length;
            }

            public void MoveBytes(int splicesize) {
                //moves the binarystream to the left (<<) in bytes
                size -= splicesize;
                byte[] cutdata = new byte[size];
                for (int i = 0; i < size; i++) { cutdata[i] = data[i + splicesize]; }
                data = cutdata;
            }

            public byte this[int membytes] {
                //gets the byte at index unless its not in the array then its 0
                get { return membytes < size ? data[membytes] : byte.MinValue; }
                set { if (membytes < size) data[membytes] = value; }
            }

            public static BinaryStream operator <<(BinaryStream binstream, int membits) {
                //a left shift operator (in bits)
                binstream.MoveBytes(membits / 8);
                membits %= 8;
                if (membits == 0) return binstream;

                for (int i = 0; i < binstream.size; i++) {
                    //moves the byte at index i, then grabs the next item and appends it
                    binstream[i] <<= membits;
                    binstream[i] |= (byte) (binstream[i + 1] >> (8 - membits));
                }
                return binstream;
            }
        }

Above is a simple BinaryStream class (a bit similar to a Queue<bool>), doesn't have much functionality yet since its just for helping to solve the problem.

Temporary Solution:

byte[][] SplitData(byte[] data, int bits) {
        //setup
        byte[][] split = new byte[data.Length * 8 / bits][];
        int chunkSize = bits / 8 + 1; //chunksize in bytes
        BinaryStream bstream = new BinaryStream(data);

        for (int i = 0; i < split.Length; i++) {
            split[i] = new byte[chunkSize];
            int copy = bits; //number of bits to copy
            int j = 0; //index at split[] to copy to
            while (copy > 0) {
                if (copy < 8) {
                    //copy less than a byte
                    split[i][j] = (byte) ((bstream[0] & (255 << (8 - copy))) >> (8 - copy));
                    bstream <<= copy;
                } else {
                    //copy a full byte
                    split[i][j] = bstream[0];
                    bstream.MoveBytes(1);
                }
                copy -= 8;
                j++;
            }
        }
        return split;
    }

Time Complexity: O(n^2) where n is the data length. Space Complexity: O(n) where n is the data length.

Not the best solution nor elegant, but it works for now.

2
  • I don't understand your examples. How can the first 3 bits of 0b10011011 be 0b111? Commented Sep 11, 2022 at 6:10
  • Very sorry for the inconvenience. Probably a copy paste error or smth Commented Sep 11, 2022 at 6:21

1 Answer 1

1

Solution using IEnumerables:

IEnumerable<bool[]> SplitDataIntoBinaryChunksOfSize(byte[] data, int x)
{
    var currentId = 0;
    var currentArray = new bool[x];
    foreach (var bit in EnumerateBits(data))
    {
        currentArray[currentId] = bit;
        currentId++;
        if(currentId == x)
        {
            yield return currentArray;
            currentArray = new bool[x];
            currentId = 0;
        }
    }
    if(currentId > 0)
        yield return currentArray;
    
}

private static readonly byte[] bits = { 128, 64, 32, 16, 8, 4, 2, 1 };

IEnumerable<bool> EnumerateBits(byte[] data)
{
    foreach (var d in data)
        foreach (var b in bits)
            yield return Convert.ToBoolean(d & b);
}

And in .Net 6 it's even simpler:

IEnumerable<bool[]> SplitDataIntoBinaryChunksOfSize(byte[] data, int x)
{
    return Enumerable.Chunk(EnumerateBits(data), x);
}

private static readonly byte[] bits = { 128, 64, 32, 16, 8, 4, 2, 1 };

IEnumerable<bool> EnumerateBits(byte[] data)
{
    foreach (var d in data)
        foreach (var b in bits)
            yield return Convert.ToBoolean(d & b);
}

But in that solution the last array will be smaller if there's leftover data.

Sign up to request clarification or add additional context in comments.

2 Comments

in the .net 6 example, is line 4 supposed to be "return Enumerable.Chunk(EnumerateBits(data), x);" instead of "3"? thanks btw
Of course yes sorry. I'll edit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.