diff --git a/PowerKit.Tests/FileExtensionsTests.cs b/PowerKit.Tests/FileExtensionsTests.cs
new file mode 100644
index 0000000..cbd3301
--- /dev/null
+++ b/PowerKit.Tests/FileExtensionsTests.cs
@@ -0,0 +1,134 @@
+using System.IO;
+using System.Threading.Tasks;
+using FluentAssertions;
+using PowerKit;
+using PowerKit.Extensions;
+using Xunit;
+
+namespace PowerKit.Tests;
+
+public class FileExtensionsTests
+{
+ [Fact]
+ public async Task WriteAllZeroes_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+
+ // Act
+ File.WriteAllZeroes(tempFile.Path, 1024);
+
+ // Assert
+ var bytes = await File.ReadAllBytesAsync(tempFile.Path);
+ bytes.Should().HaveCount(1024);
+ bytes.Should().AllSatisfy(b => b.Should().Be(0));
+ }
+
+ [Fact]
+ public void ReadAllBytes_WithOffset_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act
+ var bytes = File.ReadAllBytes(tempFile.Path, offset: 2L);
+
+ // Assert
+ bytes.Should().Equal(3, 4, 5);
+ }
+
+ [Fact]
+ public void ReadAllBytes_WithOffset_AtEndOfFile_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act
+ var bytes = File.ReadAllBytes(tempFile.Path, offset: 5L);
+
+ // Assert
+ bytes.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void ReadAllBytes_WithOffset_PastEndOfFile_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act & Assert
+ var bytes = File.ReadAllBytes(tempFile.Path, offset: 10L);
+ bytes.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void ReadAllBytes_WithOffsetAndLength_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act
+ var bytes = File.ReadAllBytes(tempFile.Path, offset: 1L, length: 3);
+
+ // Assert
+ bytes.Should().Equal(2, 3, 4);
+ }
+
+ [Fact]
+ public async Task ReadAllBytesAsync_WithOffset_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act
+ var bytes = await File.ReadAllBytesAsync(tempFile.Path, offset: 2L);
+
+ // Assert
+ bytes.Should().Equal(3, 4, 5);
+ }
+
+ [Fact]
+ public async Task ReadAllBytesAsync_WithOffset_AtEndOfFile_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act
+ var bytes = await File.ReadAllBytesAsync(tempFile.Path, offset: 5L);
+
+ // Assert
+ bytes.Should().BeEmpty();
+ }
+
+ [Fact]
+ public async Task ReadAllBytesAsync_WithOffset_PastEndOfFile_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act & Assert
+ var bytes = await File.ReadAllBytesAsync(tempFile.Path, offset: 10L);
+ bytes.Should().BeEmpty();
+ }
+
+ [Fact]
+ public async Task ReadAllBytesAsync_WithOffsetAndLength_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ File.WriteAllBytes(tempFile.Path, [1, 2, 3, 4, 5]);
+
+ // Act
+ var bytes = await File.ReadAllBytesAsync(tempFile.Path, offset: 1L, length: 3);
+
+ // Assert
+ bytes.Should().Equal(2, 3, 4);
+ }
+}
diff --git a/PowerKit/Extensions/FileExtensions.cs b/PowerKit/Extensions/FileExtensions.cs
new file mode 100644
index 0000000..a696055
--- /dev/null
+++ b/PowerKit/Extensions/FileExtensions.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PowerKit.Extensions;
+
+internal static class FileExtensions
+{
+ extension(File)
+ {
+ ///
+ /// Creates a file at the specified path and fills it with zeroes.
+ ///
+ public static void WriteAllZeroes(string path, long count)
+ {
+ using var stream = new FileStream(
+ path,
+ FileMode.Create,
+ FileAccess.Write,
+ FileShare.None
+ );
+
+ stream.SetLength(count);
+ }
+
+ ///
+ /// Reads all bytes from the specified file starting at the given offset.
+ ///
+ 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);
+
+ if (offset >= stream.Length)
+ {
+ return [];
+ }
+
+ var buffer = new byte[checked((int)(stream.Length - offset))];
+ stream.ReadExactly(buffer);
+
+ return buffer;
+ }
+
+ ///
+ /// Reads the specified number of bytes from the file starting at the given offset.
+ ///
+ public static byte[] ReadAllBytes(string path, long offset, int length)
+ {
+ using var stream = new FileStream(
+ path,
+ FileMode.Open,
+ FileAccess.Read,
+ FileShare.ReadWrite
+ );
+
+ stream.Seek(offset, SeekOrigin.Begin);
+
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length));
+ }
+
+ var buffer = new byte[length];
+ stream.ReadExactly(buffer);
+
+ return buffer;
+ }
+
+ ///
+ /// Reads all bytes from the specified file starting at the given offset asynchronously.
+ ///
+ public static async Task 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);
+
+ if (offset >= stream.Length)
+ {
+ return [];
+ }
+
+ var buffer = new byte[checked((int)(stream.Length - offset))];
+ await stream.ReadExactlyAsync(buffer, cancellationToken).ConfigureAwait(false);
+
+ return buffer;
+ }
+
+ ///
+ /// Reads the specified number of bytes from the file starting at the given offset asynchronously.
+ ///
+ public static async Task ReadAllBytesAsync(
+ string path,
+ long offset,
+ int 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);
+
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length));
+ }
+
+ var buffer = new byte[length];
+ await stream.ReadExactlyAsync(buffer, cancellationToken).ConfigureAwait(false);
+
+ return buffer;
+ }
+ }
+}