使用StreamWriter的另一个进程正在使用的文件

时间:2013-11-18 04:24:07

标签: c# streamwriter

我的程序是为我练习的,但是,当我尝试编写它找到的所有目录时,它会崩溃。

我尝试了以下内容:

  • 将其写入文件流而不是文件本身
  • 使用File.Writealllines使用列表<> (这很有效,只有前5个而且没有了)
  • FileStream.Write(subdir.ToCharArray())

我不明白为什么这不起作用,我做错了什么?

static void Main(string[] args)
{
    Method(@"C:\");
}

static void Method(string dir)
{
    //crash happens here v
    StreamWriter sw = new StreamWriter(@"C:\users\"+Environment.UserName+"\desktop\log.txt",true);

    foreach (string subdir in Directory.GetDirectories(dir))
    {
        try
        {
            Console.WriteLine(subdir);
            sw.Write(subdir);
            Method(subdir);
        }
        catch (UnauthorizedAccessException)
        {
            Console.WriteLine("Error");
        }
    }
  sw.Close(); 
}

3 个答案:

答案 0 :(得分:4)

它的递归。

因为您在此处再次致电Method

Console.WriteLine(subdir);
sw.Write(subdir);
Method(subdir); // BOOM

您的文件已经打开。你不能再打开它了。

Main中打开文件一次..

static void Main(string[] args) {
    using (StreamWriter sw = new StreamWriter(@"C:\users\"+Environment.UserName+"\desktop\log.txt",true)) {
        Method(@"C:\", sw);
    }
}

然后在你的方法中接受它:

public static void Method(string dir, StreamWriter sw) {

然后当你再次打电话时:

sw.Write(subdir);
Method(subdir, sw); // pass in the streamwriter.

但请注意,您将很快开始咀嚼内存。您正在通过整个C:​​\驱动器进行递归。也许在较小的文件夹上测试它?

答案 1 :(得分:2)

在您再次使用之前,似乎没有关闭您的编写器

 public static void Method(string dir)
    {
        //crash happens here v
        StreamWriter sw = new StreamWriter(@"C:\users\"+Environment.UserName+"\desktop\log.txt",true);

        foreach (string subdir in Directory.GetDirectories(dir))
        {

            try
            {

                Console.WriteLine(subdir);
                sw.Write(subdir);
                //This line you'll call "Method" again
                Method(subdir);

            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine("Error");
            }
        }
      sw.Close(); 
    }

另外,另一个建议是,为什么不使用“System.IO.File.AppendAllText(Path,Text)”方法?它更容易使用

答案 2 :(得分:1)

我同意以上内容,但就我而言,解决方案略有不同。

    private static object locker = new object();

    private static void WriteMessageToFile(string message)
    {
        string dateStr = DateTime.Now.Date.Day.ToString()+"_"+ DateTime.Now.Date.Month.ToString()+"_"+ DateTime.Now.Date.Year.ToString();
        if (!Directory.Exists("Logs"))
        {
            DirectoryInfo di = Directory.CreateDirectory("Logs");
        }

        //Guid guidGenerator = Guid.NewGuid();
        string filePath = _env.ContentRootPath + "\\Logs\\ProcessLog_" + dateStr + ".txt";
        FileInfo fi = new FileInfo(filePath);

        lock (locker)
        {
            using (FileStream file = new FileStream(fi.FullName, FileMode.Append, FileAccess.Write, FileShare.Read))
            using (StreamWriter streamWriter = new StreamWriter(file))
            {
                streamWriter.WriteLine(message);
                streamWriter.Close();
            }
        }

    }

因为在我的asp.net核心应用程序中,以下功能在许多地方都称为异步和异步。在这种情况下,一个线程试图写入文件,另一个线程想要写入同一文件,并且发生错误。作为解决方案,我尝试了上面的方法,但是由于我试图在关闭上一个流之前先打开一个新的流,所以它也不起作用。因此,我决定编写一个安全的代码块作为解决方案。在这种情况下,由于其他线程无法到达锁定区域,因此它们通过等待上一个操作来进行写入操作,因此我能够无错误地写入文件。

我认为;背后还有另一个原因代码,原因是我在启动时使用了Singleton注册。该函数的调用程序类相互隔离。因此,他们之前不知道哪个线程被称为函数。他们的一生已经结束了。 FileStream还包装了StreamWriter,然后它也可以在没有锁的情况下工作,无论如何保证。

即使Microsoft.Extensions.Logging默认也不支持FileLoger,但我们可以编写自定义。我在下面分享了整个实现

public class FileLoger : ILogger
    {
        public static IHostingEnvironment _env;
        private static object locker = new object();

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            var message = string.Format("{0}: {1} - {2}", logLevel.ToString(), eventId.Id, formatter(state, exception));
            WriteMessageToFile(message);
        }
        private static void WriteMessageToFile(string message)
        {
            string dateStr = DateTime.Now.Date.Day.ToString()+"_"+ DateTime.Now.Date.Month.ToString()+"_"+ DateTime.Now.Date.Year.ToString();
            if (!Directory.Exists("Logs"))
            {
                DirectoryInfo di = Directory.CreateDirectory("Logs");
            }

            //Guid guidGenerator = Guid.NewGuid();
            string filePath = _env.ContentRootPath + "\\Logs\\ProcessLog_" + dateStr + ".txt";
            FileInfo fi = new FileInfo(filePath);

            lock (locker)
            {
                using (FileStream file = new FileStream(fi.FullName, FileMode.Append, FileAccess.Write, FileShare.Read))
                using (StreamWriter streamWriter = new StreamWriter(file))
                {
                    streamWriter.WriteLine(message);
                    streamWriter.Close();
                }
            }

        }
        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }
        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }
    }

    public class FileLogProvider : ILoggerProvider
    {

        public FileLogProvider(IHostingEnvironment env)
        {
            FileLoger._env = env;
        }

        public ILogger CreateLogger(string category)
        {
            return new FileLoger();
        }
        public void Dispose()
        {

        }
    }