Skip to content

Instantly share code, notes, and snippets.

@albertofwb
Last active July 6, 2018 02:11
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save albertofwb/026338ad02b2de3ea68f9bd0177b6c33 to your computer and use it in GitHub Desktop.
test call File.Replace() multiple times check if that will cause file locke by kernel
using System;
using System.IO;
using System.Text;
namespace TestDemo
{
public class Atomic
{
private readonly object _lock = new object();
private static string BackupPath(string path)
{
return path + ".bak";
}
private void InnerRead(string path, Action<Stream> action)
{
using (var stream = new FileStream(path,
FileMode.OpenOrCreate,
FileAccess.Read,
FileShare.None,
0x10000,
FileOptions.SequentialScan))
{
action(stream);
}
}
/// <summary>
/// Run a read action over a file by name.
/// Access is optimised for sequential scanning.
/// No file share is permitted.
/// </summary>
/// <param name="path">File path to read</param>
/// <param name="action">Action to consume file stream. You do not need to close the stream yourself.</param>
public void Read(string path, Action<Stream> action)
{
lock (_lock)
{
try
{
InnerRead(path, action);
}
catch (Exception e)
{
Console.WriteLine("InnerRead Error fallback to back file", e);
InnerRead(BackupPath(path), action);
}
}
}
/// <summary>
/// Run a write action to a file.
/// This will always rewrite the file (no appending).
/// </summary>
/// <param name="path">File path to write</param>
/// <param name="action">Action to write into file stream. You do not need to close the stream yourself.</param>
public void Write(string path, Action<Stream> action)
{
lock (_lock)
{
var tmpFile = path + ".tmp";
using (
var stream = new FileStream(tmpFile,
FileMode.Create,
FileAccess.Write,
FileShare.None,
0x10000,
FileOptions.SequentialScan)
)
{
action(stream);
}
//https://msdn.microsoft.com/en-us/library/windows/desktop/hh802690%28v=vs.85%29.aspx
if (File.Exists(path))
{
File.Replace(tmpFile, path, BackupPath(path), true);
}
else
{
File.Move(tmpFile, path);
}
}
}
}
class Program
{
private static void Write(string path, Action<Stream> action)
{
{
var tmpFile = path + ".tmp";
using (
var stream = new FileStream(tmpFile,
FileMode.Create,
FileAccess.Write,
FileShare.None,
0x10000,
FileOptions.SequentialScan)
)
{
action(stream);
}
//https://msdn.microsoft.com/en-us/library/windows/desktop/hh802690%28v=vs.85%29.aspx
if (File.Exists(path))
{
File.Replace(tmpFile, path, path + ".bak", true);
}
else
{
File.Move(tmpFile, path);
}
}
}
private static byte[] GetBuff()
{
var txt = "Here comes a bus. The bus is blue.";
return Encoding.ASCII.GetBytes(txt);
}
private static string ConfigFilePath;
private static void Init()
{
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var configDir = $"{appData}\\Nutstore\\config";
if (!Directory.Exists(configDir))
{
Console.WriteLine($"Create Dir {configDir}");
}
ConfigFilePath = Path.Combine(configDir, "AlbConfig.json");
}
private static void TestAtomicWrite()
{
var buff = GetBuff();
Console.WriteLine("write");
new Atomic().Write(ConfigFilePath,
stream => { stream.Write(buff, 0, buff.Length); });
}
private static Atomic atomic = new Atomic();
private static void TestAtomicRead()
{
if (File.Exists(ConfigFilePath))
{
Console.WriteLine("read");
atomic.Read(ConfigFilePath, stream =>
{
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
reader.ReadToEnd();
}
});
}
}
static void Main(string[] args)
{
Init();
for (int i = 0; i < 100; i++)
{
Console.WriteLine("TEST no." + i);
TestAtomicWrite();
TestAtomicRead();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment