在C#中将int []转换为byte []

soa*_*dos 40 c# arrays type-conversion

我知道如何做到这一点:通过创建一个必要大小的字节数组并使用for循环来转换int数组中的每个元素.

我想知道是否有更快的方法,因为如果int大于一个方法,上面的方法似乎会破裂sbyte.

Dan*_*rth 85

如果你想要一个按位复制,即从一个int中获取4个字节,那么使用Buffer.BlockCopy:

byte[] result = new byte[intArray.Length * sizeof(int)];
Buffer.BlockCopy(intArray, 0, result, 0, result.Length);
Run Code Online (Sandbox Code Playgroud)

不要使用Array.Copy,因为它会尝试转换而不仅仅是复制.有关详细信息,请参阅MSDN页面上的备注.

  • @Moop `int[] result = new int[byteArray.Length / sizeof(int)]; Buffer.BlockCopy(byteArray, 0, result, 0, result.Length);` (3认同)
  • 你也可以使用下面的代码,如果你不知道值类型数组的元素类型编译时间:`byte [] result = new byte [Buffer.ByteLength((Array)valueTypeArray)];` (3认同)
  • 它如何知道每个 int 获得 4 个字节? (2认同)
  • 只是对 Daniel 提供的逆向解决方案(从 byte[] 到 int[])的更正,它应该是: Buffer.BlockCopy(byteArray, 0, result, 0, byteArray.Length); => 基本上最后一个参数不应该是 result.Length 而是 byteArray,Length (2认同)

Xan*_*vis 8

一个有点旧的线程,现在是 2022 年\xe2\x80\xa6 \n我周围
有一堆s (抱歉,没有s ;-) ),并且认为将它们作为字节数组来代替会很酷。在阅读了所有不同的解决方法之后,我非常困惑,并开始对我最喜欢的方法进行基准测试。\n(代码应该很容易应用于任何基本类型。)\n它用于进行实际测试和统计分析。shortint

BenchmarkDotNet

\n
using System;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Running;\n\nnamespace ArrayCastingBenchmark;\n\npublic class Benchy {\n    private const int number_of_shorts = 100000;\n    private readonly short[] shorts;\n\n    public Benchy() {\n        Random r = new(43);\n        shorts = new short[number_of_shorts];\n        for (int i = 0; i < number_of_shorts; i++)\n            shorts[i] = (short) r.Next(short.MaxValue);\n    }\n\n    [Benchmark]\n    public ReadOnlySpan<byte> SPANSTYLE() {\n        ReadOnlySpan<short> shortSpan = new ReadOnlySpan<short>(shorts);\n        return MemoryMarshal.Cast<short, byte>(shortSpan);\n    }\n\n    [Benchmark]\n    public byte[] BLOCKCOPY() {\n        byte[] bytes = new byte[shorts.Length * sizeof(short)];\n        Buffer.BlockCopy(shorts, 0, bytes, 0, bytes.Length);\n        return bytes;\n    }\n\n    [Benchmark]\n    public byte[] LINQY() {\n        return shorts.Select(i => (byte) i).ToArray();\n    }\n\n    [Benchmark]\n    public byte[] BITCONVERTER() {\n        byte[] bytes = shorts.SelectMany(BitConverter.GetBytes).ToArray();\n        return bytes;\n    }\n\n    //[Benchmark]\n    //public void BINARYWRITER() {\n    //    var fhandle = File.OpenHandle("_shorts_binarywriter.bin", FileMode.Create, FileAccess.Write);\n    //    var binaryWriter = new BinaryWriter(new FileStream(fhandle, FileAccess.Write));\n    //    foreach (var shorty in shorts)\n    //        binaryWriter.Write(shorty);\n    //    binaryWriter.Flush();\n    //    binaryWriter.Close();\n    //    fhandle.Close();\n    //}\n}\n\ninternal class Program {\n    static void Main(string[] args) {\n        var summary = BenchmarkRunner.Run<Benchy>();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我留下了最后一个,因为如果你只是File.WriteAllBytes在所有方法的末尾添加一个并让它们实际产生一些输出,突然变得比我的机器上BLOCKCOPY稍微快一些。SPANSTYLE如果其他人经历过这种情况或知道这种情况如何发生,请告诉我。

\n

编辑:\n抱歉,忘记包含实际结果(请注意:在我的机器上),因为它在标准设置和所有预热下运行了相当长的一段时间。

\n
 |       Method |              Mean |           Error |          StdDev |\n |------------- |------------------:|----------------:|----------------:|\n |    SPANSTYLE |         0.4592 ns |       0.0333 ns |       0.0666 ns |\n |    BLOCKCOPY |    15,384.8031 ns |     304.6014 ns |     775.3079 ns |\n |        LINQY |   175,187.7816 ns |   1,119.2713 ns |   1,046.9671 ns |\n | BITCONVERTER | 9,053,750.0355 ns | 330,414.7870 ns | 910,058.2814 ns |\n
Run Code Online (Sandbox Code Playgroud)\n

  • Span 速度如此之快的原因在于它实际上并不创建数据的副本。Span 只是一个美化的指针。因此,您的所有代码所做的就是创建一个指向相同数据的新指针。另外,您的 LINQ 测试不正确。仅仅将一个short转换为一个字节就会丢失信息,因为一个short可以保存16位数据,而一个字节只能保存8位数据 (4认同)

hel*_*ker 5

除了已接受的答案(我现在正在使用),Linq爱好者的替代单行程将是:

byte[] bytes = ints.SelectMany(BitConverter.GetBytes).ToArray(); 
Run Code Online (Sandbox Code Playgroud)

不过,我想,它会慢一点......