Can a Byte[] Array be written to a file in C#?
Based on the first sentence of the question: "I'm trying to write out a Byte[] array representing a complete file to a file."
The path of least resistance would be:
File.WriteAllBytes(string path, byte[] bytes)
Documented here:
System.IO.File.WriteAllBytes
- MSDN
Save byte array to file
You can use:
File.WriteAllBytes("Foo.txt", arrBytes); // Requires System.IO
If you have an enumerable and not an array, you can use:
File.WriteAllBytes("Foo.txt", arrBytes.ToArray()); // Requires System.Linq
Write and read the multiple byte[] into the file C#
You could use a BinaryWriter and a BinaryReader as shown below. First write the length of the array as an int32, then write the array bytes. Repeat for the second array. In reverse, read the length of the array as an int32, then read that many bytes. Repeat for the second array:
byte[] source = new byte[2] { 1, 2 };
byte[] dest = new byte[6] { 2, 4, 8, 16, 32, 64 };
using (FileStream fs = new FileStream("myFile.txt", FileMode.OpenOrCreate))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
bw.Write(source.Length);
bw.Write(source, 0, source.Length);
bw.Write(dest.Length);
bw.Write(dest, 0, dest.Length);
}
}
byte[] source2;
byte[] dest2;
using (FileStream fs = new FileStream("myFile.txt", FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
source2 = br.ReadBytes(br.ReadInt32());
dest2 = br.ReadBytes(br.ReadInt32());
}
}
Console.WriteLine("source = " + String.Join(" ", source));
Console.WriteLine("dest = " + String.Join(" ", dest));
Console.WriteLine("source2 = " + String.Join(" ", source2));
Console.WriteLine("dest2 = " + String.Join(" ", dest2));
Output:
source = 1 2
dest = 2 4 8 16 32 64
source2 = 1 2
dest2 = 2 4 8 16 32 64
How to write to file with a pointer (byte*) to an array of byte
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
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.
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
Writes a signed byte to the current stream and advances the stream
position by one byte.
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
Copies a block of 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)
Provides a resource pool that enables reusing instances of type 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
Provides access to unmanaged blocks of memory from managed code.
Important
This API is not CLS-compliant.
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);
}
Benchmarks
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);
}
}
Write to file from byte array in c#
Try closing or disposing the BinaryWriter, e.g.
using (var bw = new BinaryWriter(File.Open("c:\\Tmp\\" + a.Name, FileMode.OpenOrCreate)))
{
bw.Write(((FileAttachment)a).Content);
}
Also, you might want to use Path.Combine()
from now on (it will take care about the backslashes) and use @ to make directory names readable:
Path.Combine(@"c:\Tmp\", a.Name);
Related Topics
C# SQL Server - Passing a List to a Stored Procedure
An Implementation of the Fast Fourier Transform (Fft) in C#
Has an Event Handler Already Been Added
Determine the Number of Lines Within a Text File
No Output to Console from a Wpf Application
How to Detect the Character Encoding of a Text File
Response.Redirect to New Window
What Is Cool About Generics, Why Use Them
How to Read Data of an Excel File Using C#
Read Xml Attribute Using Xmldocument
How to Start Winform App Minimized to Tray
Observablecollection That Also Monitors Changes on the Elements in Collection
Deserializing JSON When Sometimes Array and Sometimes Object
How to Get Difference Between Two Dates in Year/Month/Week/Day
Rendering Partial View on Button Click in ASP.NET MVC