Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
98d914a
Add FileExtensions with WriteAllZeroes and ReadAllBytes (sync + async)
Copilot Apr 12, 2026
5aa9d98
Remove spurious bufferSize:1 from WriteAllZeroes FileStream
Copilot Apr 12, 2026
ecf7af5
Merge branch 'prime' into copilot/add-file-extensions-with-async-version
Tyrrrz Apr 12, 2026
896fb22
Update PowerKit/Extensions/FileExtensions.cs
Tyrrrz Apr 12, 2026
1663629
Fix build errors: replace FileStreamOptions with FileOptions ctor, ca…
Copilot Apr 12, 2026
a9a4a41
Change offset to long, add ReadAllBytes/Async overloads with offset+l…
Copilot Apr 12, 2026
36d7e9d
Use MemoryPool<byte>.Shared for buffer allocation in ReadAllBytes(Async)
Copilot Apr 12, 2026
f970532
Avoid redundant memory slicing by storing slice in local variable
Copilot Apr 12, 2026
5f3abb3
Merge branch 'prime' into copilot/add-file-extensions-with-async-version
Tyrrrz Apr 12, 2026
c09c408
Guard offset/length, drop MemoryPool in ReadAllBytes(Async); add edge…
Copilot Apr 12, 2026
43734d6
Return empty array instead of throwing when offset >= stream.Length
Copilot Apr 12, 2026
55cc511
Use async ReadAllBytesAsync in WriteAllZeroes_Test
Copilot Apr 12, 2026
63a574b
Guard length > int.MaxValue with ArgumentOutOfRangeException in offse…
Copilot Apr 12, 2026
7312aff
Change length parameter from long to int in offset+length overloads
Copilot Apr 12, 2026
3d8e839
Merge branch 'prime' into copilot/add-file-extensions-with-async-version
Tyrrrz Apr 12, 2026
33caa32
Use TempFile.Create() in FileExtensionsTests instead of manual temp p…
Copilot Apr 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions PowerKit.Tests/FileExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.IO;
using System.Threading.Tasks;
using FluentAssertions;
using PowerKit.Extensions;
using Xunit;

namespace PowerKit.Tests;

public class FileExtensionsTests
{
[Fact]
public void WriteAllZeroes_Test()
{
// Arrange
var path = Path.GetTempFileName();

try
{
// Act
File.WriteAllZeroes(path, 1024);

// Assert
var bytes = File.ReadAllBytes(path);
Comment thread
Tyrrrz marked this conversation as resolved.
Outdated
bytes.Should().HaveCount(1024);
bytes.Should().AllSatisfy(b => b.Should().Be(0));
}
finally
{
File.Delete(path);
}
}

[Fact]
public void ReadAllBytes_WithOffset_Test()
{
// Arrange
var path = Path.GetTempFileName();

try
{
File.WriteAllBytes(path, [1, 2, 3, 4, 5]);

// Act
var bytes = File.ReadAllBytes(path, offset: 2L);

// Assert
bytes.Should().Equal(3, 4, 5);
}
Comment thread
Tyrrrz marked this conversation as resolved.
Outdated
finally
{
File.Delete(path);
}
}

[Fact]
public void ReadAllBytes_WithOffsetAndLength_Test()
{
// Arrange
var path = Path.GetTempFileName();

try
{
File.WriteAllBytes(path, [1, 2, 3, 4, 5]);

// Act
var bytes = File.ReadAllBytes(path, offset: 1L, length: 3L);

// Assert
bytes.Should().Equal(2, 3, 4);
}
finally
{
File.Delete(path);
}
}

[Fact]
public async Task ReadAllBytesAsync_WithOffset_Test()
{
// Arrange
var path = Path.GetTempFileName();

try
{
File.WriteAllBytes(path, [1, 2, 3, 4, 5]);

// Act
var bytes = await File.ReadAllBytesAsync(path, offset: 2L);

// Assert
bytes.Should().Equal(3, 4, 5);
}
finally
{
File.Delete(path);
}
}

[Fact]
public async Task ReadAllBytesAsync_WithOffsetAndLength_Test()
{
// Arrange
var path = Path.GetTempFileName();

try
{
File.WriteAllBytes(path, [1, 2, 3, 4, 5]);

// Act
var bytes = await File.ReadAllBytesAsync(path, offset: 1L, length: 3L);

// Assert
bytes.Should().Equal(2, 3, 4);
}
finally
{
File.Delete(path);
}
}
}
119 changes: 119 additions & 0 deletions PowerKit/Extensions/FileExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace PowerKit.Extensions;

internal static class FileExtensions
{
extension(File)
{
/// <summary>
/// Creates a file at the specified path and fills it with zeroes.
/// </summary>
public static void WriteAllZeroes(string path, long count)
{
using var stream = new FileStream(
path,
FileMode.Create,
FileAccess.Write,
FileShare.None
);

stream.SetLength(count);
}

/// <summary>
/// Reads all bytes from the specified file starting at the given offset.
/// </summary>
public static byte[] ReadAllBytes(string path, long offset)
{
using var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite
);

stream.Seek(offset, SeekOrigin.Begin);

var buffer = new byte[checked((int)(stream.Length - offset))];
Comment thread
Tyrrrz marked this conversation as resolved.
stream.ReadExactly(buffer);

Comment thread
Tyrrrz marked this conversation as resolved.
return buffer;
}

/// <summary>
/// Reads the specified number of bytes from the file starting at the given offset.
/// </summary>
public static byte[] ReadAllBytes(string path, long offset, long length)
{
using var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite
);

stream.Seek(offset, SeekOrigin.Begin);

var buffer = new byte[checked((int)length)];
stream.ReadExactly(buffer);

Comment thread
Tyrrrz marked this conversation as resolved.
Comment thread
Tyrrrz marked this conversation as resolved.
return buffer;
}

/// <summary>
/// Reads all bytes from the specified file starting at the given offset asynchronously.
/// </summary>
public static async Task<byte[]> ReadAllBytesAsync(
string path,
long offset,
CancellationToken cancellationToken = default
)
{
using var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
bufferSize: 4096,
FileOptions.Asynchronous
);

stream.Seek(offset, SeekOrigin.Begin);

var buffer = new byte[checked((int)(stream.Length - offset))];
await stream.ReadExactlyAsync(buffer, cancellationToken).ConfigureAwait(false);

return buffer;
Comment thread
Tyrrrz marked this conversation as resolved.
}

/// <summary>
/// Reads the specified number of bytes from the file starting at the given offset asynchronously.
/// </summary>
public static async Task<byte[]> ReadAllBytesAsync(
string path,
long offset,
long length,
CancellationToken cancellationToken = default
)
{
using var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite,
bufferSize: 4096,
FileOptions.Asynchronous
);

stream.Seek(offset, SeekOrigin.Begin);

var buffer = new byte[checked((int)length)];
Comment thread
Tyrrrz marked this conversation as resolved.
Outdated
await stream.ReadExactlyAsync(buffer, cancellationToken).ConfigureAwait(false);

Comment thread
Tyrrrz marked this conversation as resolved.
Comment thread
Tyrrrz marked this conversation as resolved.
return buffer;
}
}
}