Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 读写二进制文件的最快方法_C#_File Io_Binary - Fatal编程技术网

C# 读写二进制文件的最快方法

C# 读写二进制文件的最快方法,c#,file-io,binary,C#,File Io,Binary,我目前正在优化一个应用程序,经常执行的操作之一是读取和写入二进制文件。我需要两种类型的函数: Set(byte[] target, int index, int value); int Get(byte[] source, int index); 这些函数是有符号和无符号短、int和long(以大端和小端顺序)所必需的 以下是我举的一些例子,但我需要对其优缺点进行评估: 第一种方法是使用封送将值写入字节[]的内存中,第二种方法是使用普通指针来完成此操作,第三种方法使用位转换器和块复制来完成此

我目前正在优化一个应用程序,经常执行的操作之一是读取和写入二进制文件。我需要两种类型的函数:

Set(byte[] target, int index, int value);

int Get(byte[] source, int index);
这些函数是有符号和无符号短、int和long(以大端和小端顺序)所必需的

以下是我举的一些例子,但我需要对其优缺点进行评估:

第一种方法是使用封送将值写入字节[]的内存中,第二种方法是使用普通指针来完成此操作,第三种方法使用位转换器和块复制来完成此操作

unsafe void Set(byte[] target, int index, int value)
{
    fixed (byte* p = &target[0])
    {
        Marshal.WriteInt32(new IntPtr(p), index, value);
    }
}

unsafe void Set(byte[] target, int index, int value)
{
    int* p = &value;
    for (int i = 0; i < 4; i++)
    {
        target[offset + i] = *((byte*)p + i);
    }
}

void Set(byte[] target, int index, int value)
{
    byte[] data = BitConverter.GetBytes(value);
    Buffer.BlockCopy(data, 0, target, index, data.Length);
}
需要进行边界检查,但这还不是我问题的一部分

如果有人能告诉我在这种情况下什么是最好、最快的方法,或者给我一些其他的解决方案,我会很高兴。最好是通用解决方案


我刚刚做了一些性能测试,结果如下:

设置封送:45毫秒,设置指针:48毫秒,设置位转换器:71毫秒 获取封送:45毫秒,获取指针:26毫秒,获取位转换器:30毫秒


似乎使用指针是最快的方法,但我认为封送和位转换器会做一些内部检查。。。有人能验证这一点吗?

您应该对代码进行一些分析,以揭示这是否是瓶颈。同时查看您的代码,您似乎正在使用.Net函数调用将一个字节写入非托管数组,包括内存上的pin和对不安全代码的调用

您最好声明一个.Net System.IO.MemoryStream并对其进行查找和写入,尽可能使用流编写器将您的更改推入其中,这样可以减少函数调用,并且不需要不安全的代码。如果你在做DSP之类的事情,需要对数组中的每个值执行单个操作,那么你会发现指针在C#中更有用

编辑:
我还要提到的是,根据您所做的工作,您可能会发现CPU缓存将生效,如果您能够继续使用适合缓存的单个小内存区域,那么您最终将获得最佳性能。

重要提示:如果您只需要一个端点,请参见wj32/dtb提供的指针魔术


就我个人而言,我会直接写入
(可能需要一些缓冲),然后重新使用一个我通常认为是干净的共享缓冲区。然后,您可以创建一些快捷方式并假定索引为0/1/2/3

当然不要使用
位转换器
,因为它不能同时用于小/大端,这是您需要的。我也倾向于只使用位移位,而不是不安全的移位等。基于以下几点,它实际上是最快的(所以我很高兴我已经这样做了,我的代码,寻找
EncodeInt32Fixed
):

Set1:371ms
Set2:171毫秒
Set3:993ms
Set4:91ms>8);
目标[索引++]=(字节)(值>>16);
目标[索引]=(字节)(值>>24);
}
}

指针是一种方法。使用fixed关键字固定对象非常便宜,并且可以避免调用WriteInt32和BlockCopy等函数的开销。对于“通用解决方案”,您可以简单地使用void*和您自己的memcpy(因为您处理的是少量数据)。但是指针不能与真正的泛型一起工作。

使用Marc Gravell的
Set1
Set4
和下面的
Set5
,我在我的机器上得到以下数字:

Set1: 197ms
Set2: 102ms
Set3: 604ms
Set4: 68ms
Set5: 55ms <==== pointer magic ;-p

当然,当字节数组不是固定在每次迭代上,而是只固定一次时,它会变得更快

Set6: 10ms (little endian)
Set7: 85ms (big endian)
代码:

if(!BitConverter.IsLittleEndian)
{
抛出新的NotSupportedException();
}
watch=Stopwatch.StartNew();
固定(字节*p=缓冲区)
{
for(int i=0;i
你有代码,为什么不运行它并用秒表进行测试呢?:/:\n你说得对,我会快速地编辑我的问题,但这不是我文章的唯一要点。我正在寻找替代方法,也许是通用的方法来解决这个问题:转换为二进制应该只对I/O是必要的。I/O操作本身总是比调整位慢几个数量级。最好的优化不能给你带来超过百分之几的改善。我不认为Stream是一个好的解决方案,问题是可能需要搜索,而且数据并非总是按顺序读写的。另一个问题是持久性。我需要先验证这一点,可能会接受这个答案作为解决方案,那么获取/阅读呢?相同,但相反<代码>返回((int)缓冲区[index++])|(((int)缓冲区[index++]))我认为这种转移的解决方案目前是最好的,最大的优势是易于endian交换。问题是,这可能是一个瓶颈,因为应用程序正在与大量不同的网络设备进行通信,并且运行在低成本的机器上,其中一些设备使用重协议,而另一些则不使用。你知道一种好的方法来rofile接口?问题是网络的可变延迟。那么你显然没有正确编写代码。你真的认为使用位移位(每个Int32至少有8条指令)吗比使用简单的mov指令快吗?我说的是将缓冲区固定在循环之外。你能在c#中给我举个例子吗?你说的是第二种集合方法,不是吗?我只需要普通值类型:Int16、UInt16、Int32、UInt32、Int64、uint64固定(byte*b=array){for(…)(int)(b+offset)=value;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
static class Program
{
    static void Main()
    {
        const int LOOP = 10000000, INDEX = 100, VALUE = 512;
        byte[] buffer = new byte[1024];
        Stopwatch watch;

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set1(buffer, INDEX, VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set1: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set2(buffer, INDEX, VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set2: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set3(buffer, INDEX, VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set3: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set4(buffer, INDEX, VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set4: " + watch.ElapsedMilliseconds + "ms");

        Console.WriteLine("done");
        Console.ReadLine();
    }
    unsafe static void Set1(byte[] target, int index, int value)
    {
        fixed (byte* p = &target[0])
        {
            Marshal.WriteInt32(new IntPtr(p), index, value);
        }
    }

    unsafe static void Set2(byte[] target, int index, int value)
    {
        int* p = &value;
        for (int i = 0; i < 4; i++)
        {
            target[index + i] = *((byte*)p + i);
        }
    }

    static void Set3(byte[] target, int index, int value)
    {
        byte[] data = BitConverter.GetBytes(value);
        Buffer.BlockCopy(data, 0, target, index, data.Length);
    }
    static void Set4(byte[] target, int index, int value)
    {
        target[index++] = (byte)value;
        target[index++] = (byte)(value >> 8);
        target[index++] = (byte)(value >> 16);
        target[index] = (byte)(value >> 24);
    }
}
Set1: 197ms
Set2: 102ms
Set3: 604ms
Set4: 68ms
Set5: 55ms <==== pointer magic ;-p
unsafe static void Set5(byte[] target, int index, int value)
{
    fixed (byte* p = &target[index])
    {
        *((int*)p) = value;                
    }
}
Set6: 10ms (little endian)
Set7: 85ms (big endian)
if (!BitConverter.IsLittleEndian)
{
    throw new NotSupportedException();
}

watch = Stopwatch.StartNew();
fixed (byte* p = buffer)
{
    for (int i = 0; i < LOOP; i++)
    {
        *((int*)(p + INDEX)) = VALUE;
    }
}
watch.Stop();
Console.WriteLine("Set6: " + watch.ElapsedMilliseconds + "ms");

watch = Stopwatch.StartNew();
fixed (byte* p = buffer)
{
    for (int i = 0; i < LOOP; i++)
    {
        *((int*)(p + INDEX)) = System.Net.IPAddress.HostToNetworkOrder(VALUE);
    }
}
watch.Stop();
Console.WriteLine("Set7: " + watch.ElapsedMilliseconds + "ms");