diff --git a/PowerKit.Tests/LockFileTests.cs b/PowerKit.Tests/LockFileTests.cs
new file mode 100644
index 0000000..7c1dc5b
--- /dev/null
+++ b/PowerKit.Tests/LockFileTests.cs
@@ -0,0 +1,52 @@
+using System.IO;
+using FluentAssertions;
+using PowerKit;
+using Xunit;
+
+namespace PowerKit.Tests;
+
+public class LockFileTests
+{
+ [Fact]
+ public void TryAcquire_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+
+ // Act
+ using var lockFile = LockFile.TryAcquire(tempFile.Path);
+
+ // Assert
+ lockFile.Should().NotBeNull();
+ File.Exists(tempFile.Path).Should().BeTrue();
+ }
+
+ [Fact]
+ public void TryAcquire_AlreadyLocked_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ using var lockFile = LockFile.TryAcquire(tempFile.Path);
+
+ // Act
+ using var lockFile2 = LockFile.TryAcquire(tempFile.Path);
+
+ // Assert
+ lockFile2.Should().BeNull();
+ }
+
+ [Fact]
+ public void Dispose_Test()
+ {
+ // Arrange
+ using var tempFile = TempFile.Create();
+ var lockFile = LockFile.TryAcquire(tempFile.Path);
+
+ // Act
+ lockFile!.Dispose();
+
+ // Assert: lock can be reacquired after disposal
+ using var lockFile2 = LockFile.TryAcquire(tempFile.Path);
+ lockFile2.Should().NotBeNull();
+ }
+}
diff --git a/PowerKit/LockFile.cs b/PowerKit/LockFile.cs
new file mode 100644
index 0000000..ced66ff
--- /dev/null
+++ b/PowerKit/LockFile.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+namespace PowerKit;
+
+///
+/// Represents a file-based lock that prevents concurrent access to a shared resource.
+///
+internal partial class LockFile(FileStream fileStream) : IDisposable
+{
+ ///
+ public void Dispose() => fileStream.Dispose();
+}
+
+internal partial class LockFile
+{
+ ///
+ /// Tries to acquire a lock on the specified file path.
+ /// Returns if the lock could not be acquired.
+ ///
+ public static LockFile? TryAcquire(string filePath)
+ {
+ try
+ {
+ var fileStream = File.Open(
+ filePath,
+ FileMode.OpenOrCreate,
+ FileAccess.ReadWrite,
+ FileShare.None
+ );
+
+ return new LockFile(fileStream);
+ }
+ // This is the most specific exception for "access denied"
+ catch (IOException)
+ {
+ return null;
+ }
+ }
+}