将byte []转换为基元数组的快速且内存有效的方法

时间:2013-01-08 20:20:23

标签: c# bytearray

我传递了一个字节数组,然后使用System.Buffer.BlockCopy将其转换为基元数组。基本上我的代码看起来像这样:

    void Convert(byte[] b)
    {
        int[] i1 = new int[100];    // real arrays much larger
        double[] d1 = new double[100];
        int iPos=0, iSize;

        iSize = i1.Length * sizeof(int);
        System.Buffer.BlockCopy(b, iPos, i1, 0, iSize);
        iPos += iSize;

        iSize = d1.Length * sizeof(double);
        System.Buffer.BlockCopy(b, iPos, d1, 0, iSize);
        iPos += iSize;

        //etc: lots of arrays

        b=null;         
    }

这是非常高效的,但它的内存使用量明显是我的字节数组的2倍,直到b被释放。

有没有办法直接将字节数组的部分转换为原始数组?一个不涉及复制数据(因此不会使内存使用量增加一倍),并且可能更快?

3 个答案:

答案 0 :(得分:3)

您可以使用不安全代码(如果您被允许使用,我不会这样做)。但你可以尝试这样的事情(不需要使用额外的数组,只需要字节数组):

    unsafe public void Convert(void* b)
    {
        int i;

        double* asDouble = (double*)b;
        double sum1 = 0.0;
        for (i = 0; i < 100; i++, asDouble++)
            sum1 += *asDouble;

        int* asInt = (int*)asDouble;
        int sum2 = 0;
        for (i = 0; i < 100; i++, asInt++)
            sum2 += *asInt;
    }

    public unsafe void SomeThing()
    {
        byte[] rawbytes = new byte[44000];

        // Fill the "rawbytes" array somehow

        fixed (byte* ptr = rawbytes)
        {
            Convert(ptr);
        }
    }

答案 1 :(得分:0)

可以使用不安全的代码。使用联合的一种解决方案(我的情况不适用)

namespace TestApplication
{
    using System;
    using System.Runtime.InteropServices;

    internal static class Program
    {
        private static unsafe void Main()
        {           
            var x = new ByteDoubleUnion();

            x.bytes[0] =  24;
            x.bytes[1] =  45;
            x.bytes[2] =  68;
            x.bytes[3] =  84;
            x.bytes[4] = 251;
            x.bytes[5] =  33;
            x.bytes[6] =   9;
            x.bytes[7] =  64;

            // Prints pi.
            Console.WriteLine(x.doubleValue);

            Console.ReadLine();
        }
    }

    [StructLayout(LayoutKind.Explicit)]
    internal unsafe struct ByteDoubleUnion
    {
        [FieldOffset(0)]
        internal Double doubleValue;

        [FieldOffset(0)]
        internal fixed Byte bytes[8];
    }
}

和一个解决方案只是投射指针。

namespace TestApplication
{
    using System;

    internal static class Program
    {
        private static unsafe void Main()
        {           
            var bytes = new Byte[] { 24, 45, 68, 84, 251, 33, 9, 64 };

            fixed (Byte* p = &bytes[0])
            {
                // Prints pi, too.
                Console.WriteLine(*((Double*)p));
            }

            Console.ReadLine();
        }
    }
}

答案 2 :(得分:0)

这是一个使用联合数组结构的尝试(与其他帖子中的struct数组不同),因为这应该更快。

[StructLayout(LayoutKind.Explicit)]
public unsafe struct ByteBuffer
{        
    public const int IntSize=10;
    public const int DoubleSize=5;
    public const int IntBytes=sizeof(int)*IntSize;
    public const int DoubleBytes=sizeof(double)*DoubleSize;

    // Int array is unioned with byte array
    [FieldOffset(0)]
    fixed int int_array[IntSize];
    [FieldOffset(0)]
    fixed byte int_array_bytes[IntBytes];

    // Double array us unioned with byte array
    [FieldOffset(IntBytes)]
    fixed double double_array[DoubleSize];
    [FieldOffset(IntBytes)]
    fixed byte double_array_bytes[DoubleBytes];

    // Take array of bytes and distribute it 
    // by byte to each array
    public ByteBuffer(byte[] b)
    {
        fixed(byte* ptr=int_array_bytes)
        {
            for(int i=0; i<IntBytes; i++)
            {
                ptr[i]=b[i];
            }
        }
        fixed(byte* ptr=double_array_bytes)
        {

            for(int i=0; i<DoubleBytes; i++)
            {
                ptr[i]=b[IntBytes+i];
            }
        }
    }
    // Convert unmanaged array to managed array
    public int[] ToIntArray()
    {
        int[] result=new int[IntSize];
        fixed(int* ptr=int_array)
        {
            for(int i=0; i<IntSize; i++)
            {
                result[i]=ptr[i];
            }
        }
        return result;
    }
    // Convert unmanaged array to managed array
    public double[] ToDoubleArray()
    {
        double[] result=new double[DoubleSize];
        fixed(double* ptr=double_array)
        {
            for(int i=0; i<DoubleSize; i++)
            {
                result[i]=ptr[i];
            }
        }
        return result;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Load up with test data
        byte[] data=new byte[..];
        // I tested with 10 ints and 5 doubles encoded into bytes

        //Now to test the Fast conversion
        ByteBuffer bb=new ByteBuffer(data);
        int[] data1=bb.ToIntArray();
        double[] data2=bb.ToDoubleArray();
    }
}