1

私は、私をまっすぐに見つめている何かを見逃しているに違いないと思います。

ファイルが別のプロセス エラーによって開かれています。

これが私のコードです

ロガー.cs:

public class Logger
{

    /// <summary>
    /// Log File Path 
    /// </summary>
    public string LogFilePath { get; set; }

    /// <summary>
    /// Writer
    /// </summary>
    public StreamWriter Writer { get; set; }

    // This is a reference to the form so that we can use its threadsafe Invoke to calls methods on non thread safe UI controls.
    private readonly Form _form;

    /// <summary>
    ///Parameterless  Constructor
    /// </summary>
    public Logger()
    {

    }

    /// <summary>
    /// Call this constructor with the reference to the form.
    /// </summary>
    /// <param name="form"></param>
    public Logger(Form form)
    {
        _form = form;
    }

    public void CreateLogFile()
    {
        try
        {
            String filePath = string.Format("{0:yyyy-MM-dd}", DateTime.Now);

            // This is the text file created with time stamps
            var folderName = ConfigurationManager.AppSettings["FolderToCreate"];
            String txtFile = string.Format("Log{0:yyyy-MM-dd hh-mm-ss-tt}", DateTime.Now) + ".txt";
            // Given in config to read the path 
            var localhostizedLetter = ConfigurationManager.AppSettings["localhostDriveLetter"] + "//";
            //Create directory
            string pathString = Path.Combine(localhostizedLetter, folderName);
            if (!Directory.Exists(pathString))
            {
                Directory.CreateDirectory(pathString);
            }
            // Create a folder inside directory 
            // If folder exists dont create it 
            pathString = Path.Combine(pathString, filePath);
            if (!Directory.Exists(pathString))
            {
                Directory.CreateDirectory(pathString);
            }
            // create a file inside d://DataSummarisationDatetime.now//datetimewithtimestamp.txt
            // if exists please dont create it.
            pathString = Path.Combine(pathString, txtFile);
            if (!Directory.Exists(pathString))
            {
                // here my file is created and opened.
                // so I m doing a try catch to make sure if file is opened we are closing it so that nother process can use it
                File.Create(pathString).Dispose();
                var fileInfo = new FileInfo(pathString);
                IsFileLocked(fileInfo);

            }
            LogFilePath = pathString;
        }
        catch (Exception exception)
        {

            throw exception;
        }


    }

    /// <summary>
    ///  To check if File is opened by another process.
    /// </summary>
    /// <param name="file"></param>
    /// <returns></returns>
    public bool IsFileLocked(FileInfo file)
    {
        FileStream stream = null;

        try
        {
            stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
        }
        catch (IOException)
        {
            //the file is unavailable because it is:
            //still being written to
            //or being processed by another thread
            //or does not exist (has already been processed)
            return true;
        }
        finally
        {
            if (stream != null)
                stream.Close();
        }

        //file is not locked
        return false;
    }

    /// <summary>
    /// Log message using textwriter
    /// </summary>
    /// <param name="logMessage"></param>
    /// <param name="w"></param>
    public static void Log(string logMessage, TextWriter w)
    {
        w.Write("\r\n" + DateTime.Now + " " + logMessage);
        w.Flush();
    }

    /// <summary>
    /// Call this function to log your message
    /// </summary>
    /// <param name="textLog"></param>
    public void Log(string textLog)
    {
        StreamWriter sw = null;
        if (!File.Exists(LogFilePath))
        {
            try
            {
                sw = File.CreateText(LogFilePath);
            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                sw.Dispose();
            }

        }
        try
        {

            using (StreamWriter w = File.AppendText(LogFilePath))
            {
                Log(textLog, w);
                w.Close();
            }

        }
        catch (Exception exception)
        {
            throw exception;
        }

    }

    /// <summary>
    /// Call this function when it says file is already been using somewhere
    /// </summary>
    public void Dispose(string path)
    {
        File.Create(path).Close(); //Will close underlying stream
    }
}

_logger を使用した私のクラス:

 private void TimerRetailerFeedTick(object sender, EventArgs e)
    {
        //Are we already processing one?
        if (_doingRetailerFeed)
        {
            //Yes,dont start another
            return;
        }

        //Say we are doing one
        _doingRetailerFeed = true;
        _logger.CreateLogFile();
        var scrapeStat = new ScrapeStatRepository();
        var stringBuilder = new StringBuilder();
        var scrapeRepository = new ScrapeRepository();
        var manufacturers = ConfigurationManager.AppSettings["Manufacturers"];
        var countries = ConfigurationManager.AppSettings["Countries"];
        if (_maxThreads == 0)
        {
            _maxThreads = 1;
        }
        ThreadPool.SetMinThreads(_maxThreads, _maxThreads);
        ThreadPool.SetMaxThreads(_maxThreads, _maxThreads);

        var dueFeeds = scrapeRepository.GetAllDueRetailerfeedForApiManufacturersAndCountriesList(manufacturers,
                                                                                              "RetailerFeeds",
                                                                                              countries);
        // 5.   Get when the feed is last run i.e closeofplay(Datetime now) date minus the feed current updatedate got from databse and if  it is  
        //greater than 24 hours (Interval) then add it to the list of feeds that are due to run.

        // var countDoing = dueScrapes.Count();
        if (dueFeeds.Any())
        {
            _logger.Log(" Processing Retailer feeds on timer tick");
            _logger.Log(" Total due feeds to run : " + dueFeeds.Count());

            timerRetailerFeed.Interval = 15 * 60 * 1000;

            foreach (var feed in dueFeeds)
            {
                object scrapeObject = feed;
                var scrapeStatRow = scrapeStat.GetScrapeStatByScrapeId(feed.Id);
                int totalProductUrls = scrapeStatRow.TotalProductUrls;
                int urlsFound = scrapeStatRow.UrlsFound;
                int urlsNotFound = scrapeStatRow.UrlsNotFound;
                _logger.Log("   ");
                _logger.Log(" Feed details :" + feed);
                stringBuilder.Append(" && ");
                stringBuilder.Append("Retailer " + feed.Retailer.Description + " Has " + "Total Product Urls : " +
                                     totalProductUrls + "   Total Url's found : " + urlsFound +
                                     " Total Urls not found : " + urlsNotFound);

                //  stringBuilder.Append(" , ");
                //  _logger.Log(" Proceesing Retailer : " + feed.Retailer.Description);
                ThreadPool.QueueUserWorkItem(o => UpdateRetailer(scrapeObject, true));
                // _logger.Log(" Status :  finished");
            }

            //Say we have finished
            _logger.Log(" Finished doing Retailers on Timer Basis ");
            var filePath = _logger.LogFilePath;
            var systemName = Dns.GetHostName();

            _keepItDry.SendRetailerFeedNotification("Ended RetailerFeeds Interface on Server " + systemName,
                                                    stringBuilder.ToString(), filePath);

            _keepItDry.AddTolistBox(
                DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() +
                ": Ended RetailerFeeds interface ", _listBoxLog);
            //_logger.Dispose(filePath);
        }
        _doingRetailerFeed = false;
    }

スレッドプールから UpdateRetailer を呼び出しています

   private void UpdateRetailer(object scrapeObject, object value)
   {
       _logger.Log(" Writing   : " + downloadFileName);
   }

プロセスが別のプロセスによって使用されているという例外が発生するので、これを試しました:

 Invoke(new System.Action(() =>
        {
            _logger.Log(" Writing   : " + downloadFileName);
        })); 

しかし、私はまだ同じエラーが発生しています。

どんなアドバイスも役に立ちます。

4

1 に答える 1

1

書き込みを同期する必要があります。現在、複数のスレッドから呼び出し_logger.Logており、それぞれがファイルを開こうとしています。これに対処する 1 つのオプションは、起動時に書き込み用にログ ファイルを開き、それをメンバー変数 (sw) に格納してから、書き込みが必要になるたびにロックすることです。代わりにSystem.Diagnostics.TraceSourceとその仲間を使用することをお勧めします。

疑似コード:

private StreamWriter sw;

public void CreateLogFile()
{
     // ...
     sw = File.AppendText(filename);
}

public void Log(string text)
{
   lock (sw)
   {
      sw.writeLine(text);
   }
}
于 2013-10-30T01:00:51.670 に答える