[英]How to write to file with a pointer (byte*) to an array of byte
I am saving too many files large files for a mobile OS, so I am assuming I should be use byte*
for saving memory and allocations我为移动操作系统保存了太多文件大文件,所以我假设我应该使用byte*
来保存 memory 和分配
Example Code示例代码
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
}
I know I can do this with Span<T>
, but I am in Unity which doesn't support it.我知道我可以用Span<T>
做到这一点,但我在 Unity 中不支持它。 Is there another way?还有其他方法吗?
Disregarding any other problems (conceptual or otherwise).忽略任何其他问题(概念或其他)。 There are a few ways to do this.有几种方法可以做到这一点。
Convoluted examples ensue复杂的例子接踵而至
If you could use Span<T>
which can take a pointer and length and then use FileStream.Write(ReadOnlySpan<Byte>)
overload如果您可以使用Span<T>
可以采用指针和长度,然后使用FileStream.Write(ReadOnlySpan<Byte>)
重载
Writes a sequence of bytes from a read-only span to the current file stream and advances the current position within this file stream by the number of bytes written.将只读范围中的字节序列写入当前文件 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);
}
Or, just use BinaryWriter.Write
and write each byte, this is a̶ ̶l̶i̶t̶t̶l̶e̶... extremely inefficient或者,只是使用BinaryWriter.Write
并写入每个字节,这是一个̶̶l̶i̶t̶t̶l̶e̶... 效率极低
Writes a signed byte to the current stream and advances the stream position by one byte.将有符号字节写入当前 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);
Or, at the cost of an allocation , just Buffer.MemoryCopy
to a new array and Write
或者,以分配为代价,只需Buffer.MemoryCopy
到新数组并Write
Copies a block of memory.复制一块 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);
}
Or, expanding on the array copy method, you could use an ArrayPool<Byte>
for fewer allocations and in-turn will be better for your LOH (if applicable)或者,扩展数组复制方法,您可以使用ArrayPool<Byte>
来减少分配,反过来对您的LOH会更好(如果适用)
Provides a resource pool that enables reusing instances of type T[].提供一个资源池,可以重用 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);
}
Or you could use an UnmanagedMemoryStream
或者您可以使用UnmanagedMemoryStream
Provides access to unmanaged blocks of memory from managed code.提供从托管代码对 memory 的非托管块的访问。
Important重要的
This API is not CLS-compliant.此 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 |
Setup设置
[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.