C# 如何读取文本文件而不锁定磁盘上的文件?

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 )

基本上,我有一些这样的代码,可以将ASCII文本文件的内容读入列表:

    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
的对象的基本规则是,您应该始终使用
块将它们包装在

除此之外,你可能