Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在后台写入文件_C#_.net_Io - Fatal编程技术网

C# 在后台写入文件

C# 在后台写入文件,c#,.net,io,C#,.net,Io,给定一个写入文本文件的方法 public void WriteToFile( ) { var file = "C:\\AsyncTest.txt"; var writer = File.Exists( file ) ? File.AppendText( file ) : File.CreateText( file ); writer.WriteLine( "A simulated entry" ); writer.Close(); } 我需要模拟一个场景,在这个

给定一个写入文本文件的方法

public void WriteToFile( ) {
    var file = "C:\\AsyncTest.txt";
    var writer = File.Exists( file ) ? File.AppendText( file ) : File.CreateText( file );
    writer.WriteLine( "A simulated entry" );
    writer.Close();
}
我需要模拟一个场景,在这个场景中,这个方法可以在一个循环中调用,可能要调用几十次,并且必须异步运行

因此,我尝试在这样一个新线程中调用该方法(writer是WriteToFile所在的类)

它只运行了一次,但引发了一个IO异常,即该文件正被另一个进程在后续迭代中使用。事实上,这很有道理,但我不知道如何解决这个问题

我试着像这样使用Join()

Thread thread = new Thread( writer.WriteToFile );
thread.Start(  );
thread.Join();
但是这会锁定调用线程,直到所有连接的线程都完成,哪种方式会破坏目的,不是吗

我尝试使用
ThreadPool.QueueUserWorkItem(writer.WriteToFile),但得到相同的IO异常

我试着用锁

private object locker = new object();

public void WriteToFile( ) {
  lock(locker){
    //same code as above
  }
}
但这没有明显的效果

我还尝试使用Task类,但没有成功


那么,如何在不锁定调用线程的情况下,将这些后台线程“叠加”到单个文件中而不发生冲突呢?

您可以像尝试过的那样处理锁定,但需要使用
语句包含

private readonly object _lockObj = new Object();

public void WriteToFile( )
{
    var file = "C:\\AsyncTest.txt";
    lock (_lockObj)
    {
        using (StreamWriter writer = File.AppendText( file ))
        {
            writer.WriteLine( "A simulated entry" );
        }
    }
}

此外,您不需要利用
CreateText
,因为
AppendText
将创建不存在的文件。最后,我以前也遇到过这段代码的问题,因为锁将在Windows释放资源之前释放。这种情况很少见,但确实会发生,所以我只添加了一点重试逻辑来查找特定的异常。

您可以使用类似以下内容:

// To enqueue the write
ThreadPool.QueueUserWorkItem(WriteToFile, "A simulated entry");

// the lock
private static object writeLock = new object();

public static void WriteToFile( object msg ) {
    lock (writeLock) {
        var file = "C:\\AsyncTest.txt";

        // using (var writer = File.Exists( file ) ? File.AppendText( file ) : File.CreateText( file )) {
        // As written http://msdn.microsoft.com/it-it/library/system.io.file.appendtext(v=vs.80).aspx , File.AppendText will create the
        // file if it doesn't exist

        using (var writer = File.AppendText( file )) {
            writer.WriteLine( (string)msg );
        }
    }
}
请使用
和文件一起使用

  • 处理你的溪流
  • 使用TPL或异步/等待功能
  • 例如:

    Task.Run(() => File.WriteAllText("c:\\temp\test.txt", "content"));
    
    这将异步运行写操作,而无需您处理线程

    此外,streams和stream Writer提供了WriteAsync方法,您可以使用这些方法并等待它们

    更新

    要避免“锁定”问题,请不要执行锁定:) 如果尝试从不同线程写入同一文件,则会发生锁定。您可以使用File.Open()方法并指定模式,以便它阻止线程并等待文件可写

    但是阻塞是不好的。 所以我建议您,如果您想从多个线程写入,请创建一个队列并将您的写入任务放入该队列。您可以从多个线程安全地放置(使用
    ConcurrentQueue
    )。 然后在后台任务中使用该队列,只需将队列中的内容逐个写入文件


    就是这样:多个发布者,一个[文件写入]消费者,超级简单,不需要锁。

    另一个选项是创建队列。让主线程在队列上放置字符串,让一个持久性后台线程读取队列并写入文件。这真的很容易做到

    private BlockingCollection<string> OutputQueue = new BlockingCollection<string>();
    
    void SomeMethod()
    {
        var outputTask = Task.Factory.StartNew(() => WriteOutput(outputFilename),
            TaskCreationOptions.LongRunning);
    
        OutputQueue.Add("A simulated entry");
        OutputQueue.Add("more stuff");
    
        // when the program is done,
        // set the queue as complete so the task can exit
        OutputQueue.CompleteAdding();
    
        // and wait for the task to finish
        outputTask.Wait();
    }
    
    void WriteOutput(string fname)
    {
        using (var strm = File.AppendText(filename))
        {
            foreach (var s in OutputQueue.GetConsumingEnumerable())
            {
                strm.WriteLine(s);
                // if you want to make sure it's written to disk immediately,
                // call Flush. This will slow performance, however.
                strm.Flush();
            }
        }
    }
    
    private BlockingCollection OutputQueue=new BlockingCollection();
    void方法()
    {
    var outputTask=Task.Factory.StartNew(()=>WriteOutput(outputFilename),
    TaskCreationOptions.LongRunning);
    添加(“模拟条目”);
    添加(“更多内容”);
    //程序完成后,
    //将队列设置为已完成,以便任务可以退出
    OutputQueue.CompleteAdding();
    //然后等待任务完成
    outputTask.Wait();
    }
    void WriteOutput(字符串fname)
    {
    使用(var strm=File.AppendText(文件名))
    {
    foreach(OutputQueue.GetConsumingEnumerable()中的变量s)
    {
    标准写入线(s);
    //如果要确保它立即写入磁盘,
    //调用Flush。但是,这会降低性能。
    strm.Flush();
    }
    }
    }
    
    后台线程在输出队列上执行非忙等待,因此它不使用CPU资源,除非它实际输出数据。由于其他线程只需在队列中放入一些内容,因此基本上不需要等待


    有关更多信息,请参阅我的博客。

    尝试在全局(静态)变量的线程内锁定,并在锁定结束前(如100ms)添加一个轻微的睡眠(windows在打开和关闭文件方面存在问题)。一个文件还是多个文件?您想写的是固定的还是作为参数传递的?这是否有助于解锁文件?请使用任务。然后,您可以使用将下一个操作排队,依此类推。您打开文件的方式不能使其异步写入同一文件。为什么在此处使用
    volatile
    ?我本以为
    \u lockObj
    应该是
    只读的
    。@ken,你说得对。老实说,我不确定。也许我还需要一杯咖啡。你没有解决他的锁定问题。你没有任何锁定问题,以防你处理流(并且.writealText在内部执行此操作)如果你不想在同一时间从不同的线程写入同一个文件,如果你想从不同的线程写入同一个文件,我建议不要锁定。将更新我的答案。对不起,我应该提到我正在使用.NET 4.0——我认为Task.Run是在4.5中引入的?@AlexeyRaga
    您可以使用File.Open()方法并指定模式,这样它将阻止线程并等待文件可写。
    这我认为您无法做到(仅使用
    File.Open
    )嘿,谢谢。这是可行的——至少在这个模拟中是如此——希望它能转化为实际的应用程序:)。但是,您是否介意解释一下,如果lock对象和write方法是静态的,为什么它可以工作,但是如果它们不是静态的,为什么它会失败(如解决方案的答案所示)?顺便说一下,不需要条件<代码>文件。如果文件不存在,则AppendText
    将创建一个新文件。所以你可以使用(var writer=File.AppendText(File))编写
    你不知道吗。我的锁工作正常,我的团队认为锁坏了,想要排队……:)(很棒的博客,顺便说一下!)@四十二:很高兴你成功了。谢谢你的好话。A.
    private BlockingCollection<string> OutputQueue = new BlockingCollection<string>();
    
    void SomeMethod()
    {
        var outputTask = Task.Factory.StartNew(() => WriteOutput(outputFilename),
            TaskCreationOptions.LongRunning);
    
        OutputQueue.Add("A simulated entry");
        OutputQueue.Add("more stuff");
    
        // when the program is done,
        // set the queue as complete so the task can exit
        OutputQueue.CompleteAdding();
    
        // and wait for the task to finish
        outputTask.Wait();
    }
    
    void WriteOutput(string fname)
    {
        using (var strm = File.AppendText(filename))
        {
            foreach (var s in OutputQueue.GetConsumingEnumerable())
            {
                strm.WriteLine(s);
                // if you want to make sure it's written to disk immediately,
                // call Flush. This will slow performance, however.
                strm.Flush();
            }
        }
    }