如何无阻塞读写JSON文件?解决进程占用文件的访问错误
一直遇到“进程无法访问文件”错误,调研后未找到有效解决方案,包括相关技术社区帖子也未给出可行解法。以下是当前的代码实现及报错信息,对应的解决方案如下:
现有代码
写入进程代码
private void write2fileJson(string str, string filename, bool append = true) { // Print(str); using (System.IO.StreamWriter file1 = new System.IO.StreamWriter(filename + ".json", append)) { file1.WriteLine(str); file1.Flush(); } }
读取进程代码
using (var s = new FileStream(StrategyFileWithpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { using (var tr = new StreamReader(s)) { StrategyStateJson = tr.ReadToEnd(); } }
报错信息
System.IO.IOException: 进程无法访问文件'd:\strategyfiles\GBPUSD.json',因为该文件正由另一进程使用。
在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
在 System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
在 System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
在 NinjaTrader.NinjaScript.Indicators.ProfitabilityPlots.GetStrategyState() 位置 d:\My Documents\NinjaTrader 8\bin\Custom\Indicators\ProfitabilityPlots.cs:行号 150
在 NinjaTrader.NinjaScript.Indicators.ProfitabilityPlots.OnChanged(Object source, FileSystemEventArgs e) 位置 d:\My Documents\NinjaTrader 8\bin\Custom\Indicators\ProfitabilityPlots.cs:行号 268
在 System.IO.FileSystemWatcher.OnChanged(FileSystemEventArgs e)
在 System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* overlappedPointer)
在 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
解决方案
问题根源是StreamWriter默认以独占模式打开文件,导致读取进程无法访问。需修改写入代码,显式指定文件共享模式:
修改后的写入代码
private void write2fileJson(string str, string filename, bool append = true) { // Print(str); var filePath = filename + ".json"; // 显式创建FileStream并指定FileShare.ReadWrite,允许其他进程同时读写 using (var fs = new FileStream(filePath, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) using (System.IO.StreamWriter file1 = new System.IO.StreamWriter(fs)) { file1.WriteLine(str); file1.Flush(); } }
关键说明
- 写入时必须指定
FileShare.ReadWrite,让其他进程在写入过程中也能打开文件进行读写操作 - 现有读取代码的
FileShare.ReadWrite设置正确,无需修改 using语句已确保文件句柄及时释放,这部分无需调整
可选优化方案
如果业务场景允许,还可以考虑以下方式进一步避免冲突:
- 原子替换文件:先写入临时文件,完成后替换目标文件,避免读写过程中的内容不一致
- 跨进程同步锁:使用
Mutex等机制,在读写前获取锁,确保同一时间只有一个进程操作文件(会降低并发效率,按需选择)
内容的提问来源于stack exchange,提问作者junkone

