繁体   English   中英

如何使用指向字节数组的指针(字节*)写入文件

[英]How to write to file with a pointer (byte*) to an array of byte

我为移动操作系统保存了太多文件大文件,所以我假设我应该使用byte*来保存 memory 和分配

示例代码

private unsafe static void WriteMesh(ref MeshInfo mesh, BinaryWriter bw)
{
    var size = UnsafeUtility.SizeOf<float3>() * mesh.vertices.Length;
    byte* pByte = (byte*)mesh.vertices.GetUnsafePtr();

    bw.Write(pByte); // Obviously this wont work
}

我知道我可以用Span<T>做到这一点,但我在 Unity 中不支持它。 还有其他方法吗?

忽略任何其他问题(概念或其他)。 有几种方法可以做到这一点。

复杂的例子接踵而至

如果您可以使用Span<T>可以采用指针长度,然后使用FileStream.Write(ReadOnlySpan<Byte>)重载

将只读范围中的字节序列写入当前文件 stream 并将当前 position 在此文件 stream 中前进写入的字节数。

var bytes = new byte[] {1,2,3};
var size = bytes.Length;

using var fs = new FileStream(@"SomeAwesomeFileNamedBob.dat", FileMode.Create);

fixed (byte* p = bytes)
{
   var span = new Span<byte>(p, size);
   fs.Write(span);
}

或者,只是使用BinaryWriter.Write并写入每个字节,这是一个̶̶l̶i̶t̶t̶l̶e̶... 效率极低

将有符号字节写入当前 stream 并将 stream position 前进一个字节。

var bytes = new byte[] {1, 2, 3};
var size = bytes.Length;

using var fs = new FileStream(@"SomeAwesomeFileNamedBob.dat", FileMode.Create);
using var bw = new BinaryWriter(fs);

fixed (byte* p = bytes)
   for (int i = 0; i < size; i++)
      bw.Write(*p);

或者,以分配为代价,只需Buffer.MemoryCopy到新数组Write

复制一块 memory。

var bytes = new byte[] {1,2,3};
var size = bytes.Length;

using var fs = new FileStream(@"SomeAwesomeFileNamedBob.dat", FileMode.Create);

var temp = new byte[size];
fixed (byte* pOld = bytes,pNew = temp)
{
   Buffer.MemoryCopy(pOld,pNew,size,size);
   fs.Write(temp,0,size);
}

或者,扩展数组复制方法,您可以使用ArrayPool<Byte>来减少分配,反过来对您的LOH会更好(如果适用)

提供一个资源池,可以重用 T[] 类型的实例。

private static readonly ArrayPool<byte> _pool = ArrayPool<byte>.Shared;

...

var size = bytes.Length;

using var fs = new FileStream(@"SomeAwesomeFileNamedBob.dat", FileMode.Create);

var temp = _pool.Rent(size);
try
{
   fixed (byte* pOld = bytes, pNew = temp)
   {
      Buffer.MemoryCopy(pOld, pNew, size, size);
      fs.Write(temp, 0, size);
   }
}
finally
{
   _pool.Return(temp);
}

或者您可以使用UnmanagedMemoryStream

提供从托管代码对 memory 的非托管块的访问。

重要的

此 API 不符合 CLS。

var bytes = new byte[] {1,2,3};
var size = bytes.Length;

using var fs = new FileStream(@"SomeAwesomeFileNamedBob.dat", FileMode.Create);

fixed (byte* p = bytes)
{
   using var us = new UnmanagedMemoryStream(p,size);
   us.CopyTo(fs);
}

基准

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.630 (2004/?/20H1)
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.100
  [Host]        : .NET Core 5.0.0 (CoreCLR 5.0.20.51904, CoreFX 5.0.20.51904), X64 RyuJIT  [AttachedDebugger]
  .NET Core 5.0 : .NET Core 5.0.0 (CoreCLR 5.0.20.51904, CoreFX 5.0.20.51904), X64 RyuJIT

Job=.NET Core 5.0  Runtime=.NET Core 5.0

|          Method |  _size |         Mean |        Error |       StdDev |       Median |
|---------------- |------- |-------------:|-------------:|-------------:|-------------:|
|            Span |   1000 |     122.4 ns |      2.46 ns |      2.42 ns |     122.7 ns |
|          Single |   1000 |   5,548.3 ns |     82.61 ns |     73.23 ns |   5,561.8 ns |
|        NewArray |   1000 |     230.4 ns |      4.64 ns |     10.56 ns |     227.4 ns |
|       ArrayPool |   1000 |     185.6 ns |      3.74 ns |      4.60 ns |     186.1 ns |
| UnmanagedStream |   1000 |     249.8 ns |      4.89 ns |      8.69 ns |     247.5 ns |
|---------------- |------- |-------------:|-------------:|-------------:|-------------:|
|            Span |  10000 |   1,012.9 ns |     20.06 ns |     44.87 ns |   1,007.0 ns |
|          Single |  10000 |  56,143.2 ns |    980.01 ns |  1,436.48 ns |  56,087.6 ns |
|        NewArray |  10000 |   2,086.1 ns |     43.89 ns |    127.34 ns |   2,048.9 ns |
|       ArrayPool |  10000 |   1,277.2 ns |     24.38 ns |     50.88 ns |   1,272.3 ns |
| UnmanagedStream |  10000 |   1,267.8 ns |     24.52 ns |     28.24 ns |   1,260.9 ns |
|---------------- |------- |-------------:|-------------:|-------------:|-------------:|
|            Span | 100000 |  56,843.0 ns |  1,107.92 ns |  1,137.75 ns |  56,587.5 ns |
|          Single | 100000 | 601,186.9 ns | 11,991.48 ns | 17,576.95 ns | 598,002.9 ns |
|        NewArray | 100000 | 111,234.1 ns |  1,296.51 ns |  1,012.23 ns | 111,268.3 ns |
|       ArrayPool | 100000 |  59,183.1 ns |    278.01 ns |    232.15 ns |  59,141.8 ns |
| UnmanagedStream | 100000 |  58,539.6 ns |    941.79 ns |    834.87 ns |  58,176.1 ns |

设置

[SimpleJob(RuntimeMoniker.NetCoreApp50)]
public unsafe class DumbTest
{
   [Params(1000, 10000, 100000)] public int _size;

   private byte* _p;
   private GCHandle _handle;
   private readonly ArrayPool<byte> _pool = ArrayPool<byte>.Shared;

   [GlobalSetup]
   public void Setup()
   {
      var bytes = new byte[_size];
      new Random(42).NextBytes(bytes);
      _handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
      _p = (byte*) _handle.AddrOfPinnedObject();
   }

   [GlobalCleanup]
   public void Cleanup() => _handle.Free();

   [Benchmark]
   public void Span()
   {
      using var ms = new MemoryStream();
      var span = new Span<byte>(_p, _size);
      ms.Write(span);
   }

   [Benchmark]
   public void Single()
   {
      using var ms = new MemoryStream();
      using var bw = new BinaryWriter(ms);
      for (var i = 0; i < _size; i++)
         bw.Write(*_p);
   }

   [Benchmark]
   public void NewArray()
   {
      using var ms = new MemoryStream();

      var temp = new byte[_size];
      fixed (byte* pNew = temp)
      {
         Buffer.MemoryCopy(_p, pNew, _size, _size);
         ms.Write(temp, 0, _size);
      }
   }

   [Benchmark]
   public void ArrayPool()
   {
      using var ms = new MemoryStream();

      var temp = _pool.Rent(_size);
      try
      {
         fixed (byte* pNew = temp)
         {
            Buffer.MemoryCopy(_p,pNew,_size,_size);
            ms.Write(temp,0,_size);
         }
      }
      finally
      {
         _pool.Return(temp);
      }
   }
   [Benchmark]
   public void UnmanagedStream()
   {
      using var ms = new MemoryStream();
      using var us = new UnmanagedMemoryStream(_p, _size);
      us.CopyTo(ms);

   }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM