Last active
July 6, 2018 02:11
Star
You must be signed in to star a gist
test call File.Replace() multiple times check if that will cause file locke by kernel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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