C#进程无法访问文件''',因为它正在被另一个进程使用。

6
这段代码片段本应该将一个字符串写入名为“all_results.txt”的文本文件中。但是在使用File.WriteAllText时出现了错误。在搜索网上的解决方案后,我尝试使用FileStream和StreamWriter作为替代品。问题仍然存在。
它给了我以下错误信息:
IOException未处理:由于正在被另一个进程使用,因此无法访问文件“C:\Users\MadDebater\Desktop\ConsoleTest1\ConsoleTest\bin\Debug\all_results.txt”。
奇怪的是,这些错误随机发生。它可能在第3个循环或第45个循环期间出现错误。我提供了该类的完整代码,以防问题比看起来更深入。我确信这与我的病毒扫描器或类似的东西无关。
try
                {
                    using (FileStream stream = new FileStream(@"all_results.txt", FileMode.Create)) // Exception here
                {
                    using (StreamWriter writer = new StreamWriter(stream))
                    {
                        writer.WriteLine(result);
                        writer.Dispose();
                        writer.Close();
                    }

                    stream.Dispose();
                    stream.Close();
                }

                }
                catch (IOException ex)
                {
                    Console.WriteLine(ex);
                }

即使我尝试了这个,它仍然失败了。
try
                {
                    File.WriteAllText(@"all_results.txt", result); // Exception here
                }
                catch (IOException ex)
                {
                    Console.WriteLine(ex.Message);
                }

以下是该类的完整代码。它旨在逐个接收Twitter推文列表并使用贝叶斯分类对其进行分类。
    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using BayesClassifier;
    using System.Text.RegularExpressions;

    namespace ConsoleTest
    {
        class Analyzer
        {
            public static void Analyzing(List<string> all_results)
            {

            Reducting(all_results);
            Classifying();
        }

        public static void Reducting(List<string> all_results)
        {
            //Reductor
            //Precondition: List<string> results
            all_results.ForEach(delegate(String text)
            {

                const string ScreenNamePattern = @"@([A-Za-z0-9\-_&;]+)";
                const string HashTagPattern = @"#([A-Za-z0-9\-_&;]+)";
                const string HyperLinkPattern = @"(http://\S+)\s?";
                string result = text;

                if (result.Contains("http://"))
                {
                    var links = new List<string>();
                    foreach (Match match in Regex.Matches(result, HyperLinkPattern))
                    {
                        var url = match.Groups[1].Value;
                        if (!links.Contains(url))
                        {
                            links.Add(url);
                            result = result.Replace(url, String.Format(""));
                        }
                    }
                }

                if (result.Contains("@"))
                {
                    var names = new List<string>();
                    foreach (Match match in Regex.Matches(result, ScreenNamePattern))
                    {
                        var screenName = match.Groups[1].Value;
                        if (!names.Contains(screenName))
                        {
                            names.Add(screenName);
                            result = result.Replace("@" + screenName,
                               String.Format(""));
                        }
                    }
                }

                if (result.Contains("#"))
                {
                    var names = new List<string>();
                    foreach (Match match in Regex.Matches(result, HashTagPattern))
                    {
                        var hashTag = match.Groups[1].Value;
                        if (!names.Contains(hashTag))
                        {
                            names.Add(hashTag);
                            result = result.Replace("#" + hashTag,
                               String.Format(""));
                        }
                    }
                }

                // Write into text file
/*
                try
                {
                    using (FileStream stream = new FileStream(@"all_results.txt", FileMode.Create)) // Exception here
                {
                    using (StreamWriter writer = new StreamWriter(stream))
                    {
                        writer.WriteLine(result);
                        writer.Dispose();
                        writer.Close();
                    }

                    stream.Dispose();
                    stream.Close();
                }

                }
                catch (IOException ex)
                {
                    Console.WriteLine(ex);
                }
                */
                try
                {
                    File.WriteAllText(@"all_results.txt", result); // Exception here
                }
                catch (IOException ex)
                {
                    Console.WriteLine(ex.Message);
                }

            });
        }

        public static void Classifying()
        {
            // Classifying

            BayesClassifier.Classifier m_Classifier = new BayesClassifier.Classifier();


            m_Classifier.TeachCategory("Positive", new System.IO.StreamReader("POSfile.txt"));
            m_Classifier.TeachCategory("Negative", new System.IO.StreamReader("NEGfile.txt"));

            Dictionary<string, double> newscore;
            newscore = m_Classifier.Classify(new System.IO.StreamReader("all_results.txt"));

            PrintResults(newscore);
}

        public static void PrintResults(Dictionary<string, double> newscore)
        {
            foreach (KeyValuePair<string, double> p in newscore)
            {
                Console.WriteLine(p.Key + ", " + p.Value);
            }

            List<string> list = new List<string>();
            using (StreamReader reader = new StreamReader("all_results.txt"))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    list.Add(line);          // Add to list.
                    Console.WriteLine(line); // Write to console.

                }

                reader.Close();
            }

            //PrintSentiment(newscore);
        }

        public static void PrintSentiment(Dictionary<string, double> newscore)
        {

            // if difference < 2, neutral
            // if neg < pos, pos
            // if pos < neg, neg

            double pos = newscore["Positive"];
            double neg = newscore["Negative"];
            string sentiment = "";

            if (Math.Abs(pos - neg) < 1.03)
            {
                sentiment = "NEUTRAL";
            }
            else
            {
                if (neg < pos)
                {
                    sentiment = "POSITIVE";
                }
                else if (pos < neg)
                {
                    sentiment = "NEGATIVE";
                }
            }

            Console.WriteLine(sentiment);


            // append tweet_collection to final_results <string> list
            // append sentiment tag to the final_results <string> list
            // recursive
        }
    }
}

你为什么不使用TextWriter呢? - Iain Ward
1
我曾经在紧密循环中写入文本文件时发现过这样的错误。文件没有及时释放以供下一次迭代使用,如果要写入大量文本,则可能会出现此问题。 - Iain Ward
@w69rdy 不熟悉 TextWriter。有没有解决紧密循环问题的方法? - youngscientist
处理这个问题的最佳方法是在完成写入操作之前保持文件处于打开状态。这样可以避免你遇到的问题,同时也可以防止其他进程在你使用它时打开它。 - Iain Ward
@w69rdy,你能展示一下如何通过代码实现吗?这样更清晰明了。我对文件不是很熟悉。 - youngscientist
有没有完整源代码的解决方案? - Kiquenet
10个回答

3
不要在FileStream和StreamWriter上调用Dispose()和Close()方法,这将由using语句自动处理。

即使我只使用不使用Dispose()和Close()方法的File.WriteAllText()代码,问题仍然存在。 - youngscientist
StreamReader 也在 PrintResults 方法中手动关闭。尝试在没有该调用的情况下运行。 - Marcus
有多个线程吗?看起来你正在覆盖自己的文件,有时它被另一个线程锁定。为什么要使用带有委托的ForEach而不是普通的foreach(string text in all_results)? - Marcus

2

使用像filemon这样的实用工具来检查哪些进程正在使用文件。

更新: 根据我所读的,Process Monitor与Filemon非常相似。您可以从这两个工具中找到哪个进程在什么时候访问了您的文件。在开始监视之前,您可以为您的文件添加过滤器。

另一件事是,如果文件存在,您可以尝试锁定该文件。


根据谷歌搜索,Filemon在Windows上已经不再受支持。我尝试使用Process Monitor,但我不确定如何识别正在使用该文件的进程。能解释一下吗? - youngscientist
1
你需要使用“进程资源管理器”。启动它后,按下 CTRL+F 键,在搜索框中输入文件名的部分内容,程序将显示所有匹配该名称的句柄。 - flatline
当异常被传递时,它运行了这段代码 --> File.WriteAllText(@"all_results.txt", result); - youngscientist
第二次运行它时,结果是:<不存在的进程>(进程),3712(PID),句柄(类型),C:\ Users \ MadDebater \ Desktop \ ConsoleTest2 \ ConsoleTest \ bin \ Debug \ all_results.txt(句柄或DLL)。 - youngscientist
"private static Object lockObject = new Object();" 在类级别上。然后我调用了 "lock (lockObject){}" 来封装调用 "all_results.txt" 的行。 - youngscientist
显示剩余5条评论

1

可能是病毒扫描器或Windows索引服务正在访问该文件?


关闭病毒扫描器、Google桌面和Windows索引服务。没有运气。 - youngscientist

0

我在遇到类似问题时找到了这篇文章。给出的建议给了我灵感!因此,为了解决这个问题,我编写了以下方法

public static void ExecuteWithFailOver(Action toDo, string fileName)
{

    for (var i = 1; i <= MaxAttempts; i++)
    {
        try
        {
            toDo();

            return;
        }
        catch (IOException ex)
        {
            Logger.Warn("File IO operation is failed. (File name: {0}, Reason: {1})", fileName, ex.Message);
            Logger.Warn("Repeat in {0} milliseconds.", i * 500);

            if (i < MaxAttempts)
                Thread.Sleep(500 * i);
        }
    }

    throw new IOException(string.Format(CultureInfo.InvariantCulture,
                                        "Failed to process file. (File name: {0})",
                                        fileName));

}

然后我以以下方式使用了该方法

    Action toDo = () =>
                   {
                       if (File.Exists(fileName))
                           File.SetAttributes(fileName, FileAttributes.Normal);

                       File.WriteAllText(
                           fileName,
                           content,
                           Encoding.UTF8
                           );
                   };

    ExecuteWithFailOver(toDo, fileName);

后来分析日志后,我发现我的麻烦之源是尝试从并行线程中对同一文件进行操作。但我仍然认为使用建议的FailOver方法有一些好处。


0

尝试将文件写入调试文件夹之外的另一个目录。


尝试使用 c:/all_results.txt。 - youngscientist

0

只是一个“猜测” - 如果您将文件放置在更可预测的位置,比如'c:\ all_results.txt',是否有所帮助?


0

尝试在循环中加入Thread.Sleep(1000)。就像上面有人提到的那样,文件并不总是及时释放以进行下一次循环迭代。


0
如其他人所述,重复打开和关闭文件可能是问题的原因。一个未提及的解决方案是在处理期间保持文件处于打开状态。完成后,可以关闭该文件。

你能通过代码演示一下吗?这样更清晰明了。 - youngscientist
在foreach循环之前打开FileStream。在循环内部调用.WriteLine()。在foreach完成后,关闭FileStream。 - Pedro

0

Pedro:

正如其他人所说,重复打开和关闭文件可能是问题所在。一个未被提及的解决方案是在处理期间保持文件处于打开状态。一旦完成,可以关闭文件。

或者,另一种方法是将文本收集到 StringBuilder 或其他内存中的文本存储器中,然后在循环结束时将文本转储到文件中。


贝叶斯分类器需要一个 .txt 文件作为输入,所以我别无选择。把整个东西倒进去并不能为一条 Twitter 推文给出分类。 - youngscientist
1
然后,您可以尝试将单个推文写入文件,以便没有2次迭代写入同一文件。所有这些都是为了给操作系统足够的时间来关闭文件并释放其句柄。知道您已经写入的所有文件名可以让您逐个将它们提供给分类器。 - bugventure
关于内存中的好处是另一种替代重复文件写入的选择,这是一个很好的观点。 - Pedro

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接