写入文件时避免拒绝访问

时间:2015-06-18 12:01:20

标签: c# multithreading file logging trace

我使用以下方法登录文件

public static void LogDataContractToFile(string XMLStringToLog, string filePathAndName)
{
    FileInfo fileinfoMaster;
    FileInfo fileinfoLog;
    string fileName = string.Empty;
    int tmpInt = 0;
    filePathAndName = filePathAndName.ToLower();

    while (true)
    {
        lock (LogDataContractToFileLock)
        {
            if (!_workingWithFiles.Contains(filePathAndName))
            {
                _workingWithFiles.Add(filePathAndName);
                break;
            }
        }
        Thread.Sleep(100);
    }

    try
    {
        #region Create XMLFile

        if ((tmpInt = filePathAndName.LastIndexOf('.')) > 0)
            fileName = filePathAndName.Remove(tmpInt, filePathAndName.Length - tmpInt);
        else
            fileName = filePathAndName;

        fileinfoMaster = new FileInfo(fileName + ".xml");
        fileinfoLog = new FileInfo(fileinfoMaster.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(fileinfoMaster.Name) + ".log");

        if ((fileinfoMaster.Exists && !fileinfoLog.Exists) ||
            (!fileinfoMaster.Exists && fileinfoLog.Exists))
        {
            fileinfoMaster.Delete();
            fileinfoLog.Delete();
        }

        //Se så att filen är 50 MB eller mindre annars arkivera
        if (fileinfoMaster.Exists && fileinfoLog.Length > 52428800)
        {
            tmpInt = FileWriter.FileCount(fileinfoLog.DirectoryName, Path.GetFileNameWithoutExtension(fileinfoMaster.Name) + "*.log");
            fileinfoLog.MoveTo(Path.Combine(fileinfoLog.DirectoryName, Path.GetFileNameWithoutExtension(fileinfoLog.Name) + "_" + tmpInt.ToString() + ".log"));
            CreateLogDataMasterFile(Path.Combine(fileinfoMaster.DirectoryName, Path.GetFileNameWithoutExtension(fileinfoMaster.Name) + "_" + tmpInt.ToString() + ".xml"), fileinfoLog.Name);
            fileinfoLog = new FileInfo(fileinfoMaster.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(fileinfoMaster.Name) + ".log");
        }

        if (!fileinfoMaster.Exists)
        {
            DirectoryInfo info = new DirectoryInfo(fileinfoMaster.DirectoryName);
            if (info.Exists == false)
                info.Create();

            CreateLogDataMasterFile(fileinfoMaster.FullName, Path.GetFileNameWithoutExtension(fileinfoMaster.Name) + ".log");
        }

        #endregion

        using (StreamWriter sw = File.AppendText(fileinfoMaster.DirectoryName + "\\" + Path.GetFileNameWithoutExtension(fileinfoMaster.Name) + ".log"))
        {
            sw.Write(XMLStringToLog);
            sw.Flush();
        }
    }
    finally
    {
        lock (LogDataContractToFileLock)
        {
            _workingWithFiles.Remove(filePathAndName);
        }
    }

}

private static void CreateLogDataMasterFile(string filepathAndName, string dataFileName)
{
    XmlTextWriter xmlWriter;
    using (xmlWriter = new XmlTextWriter(filepathAndName, System.Text.Encoding.UTF8))
    {
        xmlWriter.Formatting = Formatting.Indented;
        xmlWriter.WriteStartDocument();
        xmlWriter.WriteDocType("DataLog", null, null, "<!ENTITY data SYSTEM \"" + dataFileName + "\">");
        xmlWriter.WriteStartElement("root");
        xmlWriter.WriteRaw("&data;");
        xmlWriter.WriteEndElement();
        xmlWriter.Flush();
    }
}

几个不同的线程可能同时写入文件,在某些情况下,它们会写入同一个文件。为了避免access denied, used by other process出现问题,我已经实现了一些逻辑。

问题在于我仍然不时地access denied, used by other process

我已经看过像TextWriterTraceListener和here这样的跟踪器中的构建。我可以看到以下注释:

  

如果尝试写入正在使用的文件或   不可用,文件名自动以GUID为前缀。

所以看起来甚至微软都有这个问题?这是一个Windows问题吗?有没有办法处理这个因为生成一个新文件?生成一个新文件会使文件中的数据流混乱!

1 个答案:

答案 0 :(得分:1)

是。不要从多个线程写入文件。创建一个对文件写入负责的单个线程,并让它从ConcurrentQueue读取要写入的内容。任何需要编写的线程都应该只是将数据添加到队列中。