我想我一定会错过一些直接盯着我的东西。
我正在通过另一个进程错误打开文件。
这是我的代码
Logger.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);
}));
但我仍然得到同样的错误。
任何建议都会有所帮助。
答案 0 :(得分:1)
您需要同步写入。目前,您正在从多个线程调用_logger.Log
,每个线程都会尝试打开该文件。处理此问题的一个选项是打开日志文件以便在启动时写入,将其存储到成员变量(sw),然后在每次要写入时锁定它。更好的选择是使用System.Diagnostics.TraceSource和朋友。
伪码:
private StreamWriter sw;
public void CreateLogFile()
{
// ...
sw = File.AppendText(filename);
}
public void Log(string text)
{
lock (sw)
{
sw.writeLine(text);
}
}