C# 如何读取文本文件而不锁定磁盘上的文件?
基本上,我有一些这样的代码,可以将ASCII文本文件的内容读入列表:C# 如何读取文本文件而不锁定磁盘上的文件?,c#,.net,file,parsing,streamreader,C#,.net,File,Parsing,Streamreader,基本上,我有一些这样的代码,可以将ASCII文本文件的内容读入列表: List<string> lines = new List<string> ( ); using ( StreamReader sr = File.OpenText ( textfile ) ) { string s = String.Empty; while ( ( s = sr.ReadLine ( ) ) != null )
List<string> lines = new List<string> ( );
using ( StreamReader sr = File.OpenText ( textfile ) )
{
string s = String.Empty;
while ( ( s = sr.ReadLine ( ) ) != null )
lines.Add ( s );
}
修改文件的代码:
public static void RemoveCoinFromBuyOrderLogs ( string symbol )
{
if ( !walletLocked )
{
walletLocked = true;
string [ ] lines = File.ReadAllLines ( walletFilename );
var newlines = lines.Where ( c => !c.StartsWith ( symbol + "USDT" ) && !c.StartsWith ( symbol + "BUSD" ) && !c.StartsWith ( symbol + "USDC" ) && !c.StartsWith ( symbol + "TUSD" ) ).Select ( c => c ).ToList ( );
File.WriteAllLines ( walletFilename, newlines );
using ( FileStream fs = File.Open ( walletFilename, FileMode.OpenOrCreate ) )
{
StreamWriter sw = new StreamWriter ( fs );
sw.AutoFlush = true;
newlines.ForEach ( r => sw.WriteLine ( r ) );
}
walletLocked = false;
}
}
public static void AddCoinToOrderLogs ( string newOrder, long orderId )
{
if ( !walletLocked )
{
var lines = Utility.ReadAllLines ( walletFilename );
lines = lines.Select ( line => line.Replace ( "\r", "" ) ).ToList ( );
lines = lines.Where ( line => line != "" ).Select ( line => line ).ToList ( );
var fields = lines.Select ( line => line.Split ( '\t' ) ).ToList ( );
bool duplicate = false;
foreach ( var field in fields )
{
if ( field.Length >= 5 )
{
long id = Convert.ToInt64 ( field [ 4 ] );
if ( id == orderId )
duplicate = true;
}
}
if ( !duplicate )
{
lines.Add ( newOrder );
lines.Sort ( );
walletLocked = true;
File.WriteAllLines ( walletFilename, lines );
walletLocked = false;
}
}
}
查看File.Open()
。它允许您指定其他参数以避免锁定。我认为应该这样做
例如,您可以执行var stream=newfilestream(textfile,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)
查看文件.Open()
。它允许您指定其他参数以避免锁定。我认为应该这样做
例如,您可以执行var stream=newfilestream(textfile,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)代码>
此函数用于打开文本文件,读取文件的所有行,然后关闭文件。
若文件小于4G,则可能会很有用
将结果字符串数组强制转换为列表,并对其执行任何操作。该文件保持空闲和未锁定状态。
使用writeAllines(路径、字符串线)
最后
如果真的需要实时执行,还可以使用异步方法
可能真的很有帮助。功能是
阅读
public async Task SimpleReadAsync()
{
string filePath = "simple.txt";
string text = await File.ReadAllTextAsync(filePath);
Console.WriteLine(text);
}
写作
public async Task SimpleWriteAsync()
{
string filePath = "simple.txt";
string text = $"Hello World";
await File.WriteAllTextAsync(filePath, text);
}
此函数用于打开文本文件,读取文件的所有行,然后关闭文件。
若文件小于4G,则可能会很有用
将结果字符串数组强制转换为列表,并对其执行任何操作。该文件保持空闲和未锁定状态。
使用writeAllines(路径、字符串线)
最后
如果真的需要实时执行,还可以使用异步方法
可能真的很有帮助。功能是
阅读
public async Task SimpleReadAsync()
{
string filePath = "simple.txt";
string text = await File.ReadAllTextAsync(filePath);
Console.WriteLine(text);
}
写作
public async Task SimpleWriteAsync()
{
string filePath = "simple.txt";
string text = $"Hello World";
await File.WriteAllTextAsync(filePath, text);
}
首先,如果您的应用程序是多线程的,那么不应该使用bool
guard。您应该使用线程同步工具,如锁、互斥、事件和/或信号量
此外,您的读取正在打开以供共享,但您的写入却没有
您也没有使用
块在中包装流。这是另一个问题。你不应该这样做:
StreamWriter sw = new StreamWriter(fs);
您应该这样做:
using(var sw = new StreamWriter(fs))
{
// ...
}
实现Dispose
的对象的基本规则是,您应该始终使用块将它们包装在中
除此之外,你可能不想边写边读,或者边读边写。这将给你带来巨大的竞争条件问题,当你需要调试正在发生的事情时,这些问题将很难重现
因为您没有使用async/await,所以我建议使用锁。这将一次只允许一个线程执行文件操作。没有竞争条件,没有“共享”文件
我无法测试这段代码,因为我没有要测试的数据,但请尝试让它看起来接近这一点
老实说,我认为您应该使用类似SQLite数据库的东西来完成这类工作。使用多个线程操作单个平面文件是一件很难正确有效地完成的事情
埃塔
下面是使用信号量lim
进行同步的异步/等待模式的示例
private static readonly SemaphoreSlim _smph = new SemaphoreSlim(1, 1);
private static async Task<IEnumerable<string>> ReadAllLinesAsync(
string fileName, bool removeEmptyLines = true)
{
using (var s = File.OpenText(fileName))
{
var data = await s.ReadToEndAsync().ConfigureAwait(false);
return await Task.Run(() =>
data.Split(new[] { Environment.NewLine },
removeEmptyLines ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None));
}
}
private static async Task WriteAllLinesAsync(string fileName, IEnumerable<string> lines)
{
using (var s = File.OpenWrite(fileName))
using (var sr = new StreamWriter(s))
{
var data = await Task.Run(() =>
string.Join(Environment.NewLine, lines)).ConfigureAwait(false);
await sr.WriteAsync(data);
}
}
public static async Task RemoveCoinFromBuyOrderLogsAsync(string symbol)
{
await _smph.WaitAsync().ConfigureAwait(false);
try
{
var lines = await ReadAllLinesAsync(walletFilename);
lines = lines.Where(c =>
!c.StartsWith(symbol + "USDT") &&
!c.StartsWith(symbol + "BUSD") &&
!c.StartsWith(symbol + "USDC") &&
!c.StartsWith(symbol + "TUSD"));
await WriteAllLinesAsync(walletFilename, lines);
}
finally
{
_smph.Release();
}
}
public static async Task AddCoinToOrderLogsAsync(string newOrder, long orderId)
{
await _smph.WaitAsync().ConfigureAwait(false);
try
{
var lines = await ReadAllLinesAsync(walletFilename);
var duplicate = lines.Select(line => line.Split('\t'))
.Any(x => (x.Length >= 5) && Convert.ToInt64(x[4]) == orderId);
if (!duplicate)
{
var newLines = await Task.Run(() =>
{
var newList = lines.ToList();
newList.Add(newOrder);
newList.Sort();
return newList;
});
await WriteAllLinesAsync(walletFilename, newLines);
}
}
finally
{
_smph.Release();
}
}
private static readonly SemaphoreSlim\u smph=new SemaphoreSlim(1,1);
专用静态异步任务ReadAllLinesAsync(
字符串文件名,bool removemptylines=true)
{
使用(var s=File.OpenText(文件名))
{
var data=await s.ReadToEndAsync().ConfigureAwait(false);
返回等待任务。运行(()=>
data.Split(新[]{Environment.NewLine},
removeEmptyLines?StringSplitOptions.RemoveEmptyEntries:StringSplitOptions.None));
}
}
专用静态异步任务WriteAllinesAsync(字符串文件名,IEnumerable行)
{
使用(var s=File.OpenWrite(文件名))
使用(var sr=新StreamWriter)
{
var data=wait Task.Run(()=>
Join(Environment.NewLine,lines)).ConfigureAwait(false);
等待高级WriteAsync(数据);
}
}
公共静态异步任务RemoveCoinFromBuyOrderLogsAsync(字符串符号)
{
wait _smph.WaitAsync().configurewait(false);
尝试
{
var lines=await ReadAllLinesAsync(walletFilename);
行=行。其中(c=>
!c.带(符号+“USDT”)的启动&&
!c.带(符号+“总线”)的启动&&
!c.带(符号+“USDC”)的启动&&
!c.带(符号+长牙“);
等待WriteAllinesAsync(walletFilename,行);
}
最后
{
_smph.Release();
}
}
公共静态异步任务AddCointoorOrderLogsAsync(字符串newOrder,长orderId)
{
wait _smph.WaitAsync().configurewait(false);
尝试
{
var lines=await ReadAllLinesAsync(walletFilename);
var duplicate=lines.Select(line=>line.Split('\t'))
.Any(x=>(x.Length>=5)和&Convert.ToInt64(x[4])==orderId);
如果(!重复)
{
var newLines=等待任务。运行(()=>
{
var newList=lines.ToList();
newList.Add(newOrder);
newList.Sort();
返回newList;
});
等待WriteAllinesAsync(walletFilename,换行符);
}
}
最后
{
_smph.Release();
}
}
我添加了任务。在我认为可能是CPU密集型操作的部分上运行。首先,如果你的应用程序是多线程的,你不应该使用bool
防护。您应该使用线程同步工具,如锁、互斥、事件和/或信号量
此外,您的读取正在打开以供共享,但您的写入却没有
您也没有使用
块在中包装流。这是另一个问题。你不应该这样做:
StreamWriter sw = new StreamWriter(fs);
您应该这样做:
using(var sw = new StreamWriter(fs))
{
// ...
}
实现Dispose
的对象的基本规则是,您应该始终使用块将它们包装在中
除此之外,你可能