Strange behavior on Windows setting file creation time - c#

I have a strange behavior on Windows 10 Pro. I have written the following C# code, which seems to work for 2 seconds until the file (txt/pdf) changes back TO ITS ORIGINAL modification / creation time. Maybe someone can explain that to me?
static void Main(string[] args)
{
var filePath = args[0];
var dateTimeStr = args[1];
try
{
DateTime dateTime;
var isOK = DateTime.TryParse(dateTimeStr,out dateTime);
if (!isOK)
{
Console.Write(string.Format("Could not parse date <{0}>! Try format <'2019-03-12 12:14:01 AM'> Exiting...", dateTimeStr));
return;
}
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
{
Console.Write(string.Format("File <{0}> does not exist! Exiting...",fileInfo.FullName));
return;
}
Console.Write("Will set date <{0}> on file <{1}>. Continue [yY]?", fileInfo.FullName, dateTimeStr);
var confirm = Console.ReadLine();
if (confirm.ToLower().Contains("y"))
{
// This does not work on the original file
File.SetLastAccessTime(fileInfo.FullName, dateTime);
File.SetCreationTime(fileInfo.FullName, dateTime);
File.SetLastWriteTime(fileInfo.FullName, dateTime);
Console.WriteLine("Changed date to <{0}> on file <{1}>.", fileInfo.FullName, File.GetLastWriteTime(fileInfo.FullName));
}
else
{
Console.WriteLine("Aborted!");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}

(Converting my comment to an answer:)
Use ProcMon, part of Microsoft Sysinternals, to monitor filesystem activity (and many other kinds of program activity) to see exactly why the file dates are being reset.
I'll bet your program is probably just fighting with poorly-written file/folder synchronization software, like OneDrive or DropBox or dodgy anti-virus software.

Related

How to get last five minutes logs in C# console .exe file

I am trying to get last 5 minutes logs for use to this below code. this code is given to all logs that created I only want to last 5 minute logs. how can I get anyone can please help me...
class Program
{
static void Main(string[] args)
{
WriteLogs.WriteLog("ConsoleLog", String.Format("{0} # {1}", "Log is Created at", DateTime.Now));
Console.WriteLine("Log is Written Successfully !!!");
Console.ReadLine();
}
}
class WriteLogs
{
public static bool WriteLog(string strFileName, string strMessage)
{
try
{
FileStream objFilestream = new FileStream(string.Format("{0}\\{1}", Path.GetTempPath(), strFileName), FileMode.Append, FileAccess.Write);
StreamWriter objStreamWriter = new StreamWriter((Stream)objFilestream);
objStreamWriter.WriteLine(strMessage);
objStreamWriter.Close();
objFilestream.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
}
Assuming you are appending to the same log file with same string format, you can just read the file line by line or all lines at once. But since you need last 5 minutes logs, those logs would always be near the end of the file. So lets just use the later approach (We can also read a file line by line in reverse, but its tricky and would require lot of code and considerations).
First you need to define a function which fetches the logs from a given date as below -
public static IEnumerable<string> GetLogs(string strFileName, DateTime dateTime)
{
var path = Path.Combine(Path.GetTempPath(), strFileName);
var logs = File.ReadAllLines(path).Where(w =>
{
var date = DateTime.Parse(w.Split("#")[1]);
return date >= dateTime;
});
return logs;
}
Call the above function as below to get last 5 minutes logs -
var logs = GetLogs("ConsoleLog", DateTime.Now.AddMinutes(-5));

Using C# to make decisions based on lines in text files

I need to write a C# console application that can be called by a scheduled task. What I need to do is compare two
text files of dates. One file will have more dates than the other. The application will need to compare a list of dates to the current date, and run a batch file based on the date.
If there's a date in file A that's equal to today's date, then look at file B to see if today's date is contained in file B.
If it is in file B, run batch file "B". If today's date is not listed in file B, but is in file A, run batch file "A". If today's date is not listed in either text file, do nothing.
As an example:
File A has dates of,
1/1/2015
1/8/2015
1/15/2015
1/22/2015
1/29/2015
File B has dates of,
1/15/2015
2/15/2015
3/15/2015
Let's assume today is 1/15/2015. The application checks file A and sees that today's date exists. It then goes on to check
file B and finds that todays date exits so it runs the batch file "B". If today's date was not in file B, it would run batch file "A".
If today was 1/31/2015, neither would be true, and no batch files would run.
This is what I have so far. Fyi... I'm new to C# and new to programming in general. Thanks in advance for any assistance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.IO;
namespace Automate_Script
{
class Program
{
// get today's date
private static DateTime today = DateTime.Today;
// create the string arrays to hold the dates from the text files. Initialize to null.
private static string[] dateLinesWeek = null;
private static string[] dateLinesMonth = null;
static void Main(string[] args)
{
// display today's date in console window.
Console.WriteLine("\n\t\tToday is {0}", today.ToString("d"));
// attempts to read the 'weekDates' text file.
try
{
// this is the text file that contains the dates for week-end run dates.
dateLinesWeek = File.ReadAllLines(#"C:\MyScripts\weekDates.txt");
dateLinesMonth = File.ReadAllLines(#"C:\MyScripts\monthDates.txt");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// create the process to run the batch execution.
Process p = new Process();
// iterate through the 'weekDates' text file
foreach (var weekLine in dateLinesWeek)
{
if (Convert.ToDateTime(weekLine) == today)
{
foreach (var monthLine in dateLinesMonth)
{
if (Convert.ToDateTime(monthLine) == today && Convert.ToDateTime(weekLine) == today)
{
try
{
string targetDirectory;
targetDirectory = string.Format(#"C:\MyScripts");
p.StartInfo.UseShellExecute = true;
p.StartInfo.WorkingDirectory = targetDirectory;
p.StartInfo.FileName = "monthTest.bat";
p.StartInfo.CreateNoWindow = false;
p.Start();
p.WaitForExit();
System.Threading.Thread.Sleep(3000);
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred: {0}, {1}", ex.Message, ex.StackTrace.ToString());
}
}
else
{
return;
}
}
}
else
{
try
{
string targetDirectory;
targetDirectory = string.Format(#"C:\MyScripts");
p.StartInfo.UseShellExecute = true;
p.StartInfo.WorkingDirectory = targetDirectory;
p.StartInfo.FileName = "weekTest.bat";
p.StartInfo.CreateNoWindow = false;
p.Start();
p.WaitForExit();
System.Threading.Thread.Sleep(3000);
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred: {0}, {1}", ex.Message, ex.StackTrace.ToString());
}
break;
}
}
Console.ReadLine();
//System.Threading.Thread.Sleep(3000);
}
}
}
I've tried many varieties of the above code with mostly the same results. I can typically only get the weekly script to run.
I think the reason your code is not working properly is the
else
{
return;
}
If today's date is not on the first line in the month file, the application will exit.
If I understand your requirements right you shall execute:
Script A.bat if today's date is present in file A.txt.
Script B.bat if today's date is present in file A.txt and B.txt.
If so, I would do something like the below. You may want to change the conditions when to run what script if I misunderstood your requirements.
namespace Automate_Script
{
class Program
{
static void Main(string[] args)
{
DateTime today = DateTime.Today;
// display today's date in console window.
Console.WriteLine("\n\t\tToday is {0}", today.ToString("d"));
if (!FileContainsDate(#"C:\MyScripts\weekDates.txt", today))
return; // Todays date not present in week dates, nothing shall be done.
if (FileContainsDate(#"C:\MyScripts\monthDates.txt", today))
{
RunScript("monthTest.bat");
}
else
{
RunScript("weekTest.bat");
}
Console.ReadLine();
}
private static bool FileContainsDate(string dateFile, DateTime date)
{
try
{
string[] dates = File.ReadAllLines(dateFile);
return dates.Any(line => Convert.ToDateTime(line) == date);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
private static void RunScript(string scriptFile)
{
try
{
Process p = new Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.WorkingDirectory = #"C:\MyScripts";
p.StartInfo.FileName = scriptFile;
p.StartInfo.CreateNoWindow = false;
p.Start();
p.WaitForExit();
System.Threading.Thread.Sleep(3000);
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred: {0}, {1}", ex.Message, ex.StackTrace.ToString());
}
}
}
}
First, I would describe your scenario a bit different: If the current date is in File B, then execute monthTest.bat. If not, check if it's in File A, then execute weekTest.bat. If it isn't in either one, do nothing.
You can use LINQ to query the arrays for the existence of your date:
var fileToRun = string.Empty;
if (dateLinesMonth.Any(x => Convert.ToDateTime(x) == today)
{
fileToRun = "monthTest.bat";
}
else if (dateLinesWeek.Any(x => Convert.ToDateTime(x) == today)
{
fileToRun = "weekTest.bat";
}
if (!string.IsNullOrEmpty(fileToRun))
{
// create and run process
}
OK So I seriously simplified what you had and I converted your arrays of strings to a list. I also cut out your read from file, because I didn't want to have that in dotfiddle. Here's another way to do it.
You can see the following code on dotfiddle. https://dotnetfiddle.net/QYjoqw
public static void Main()
{
var today = "1/8/2015";
// create the string arrays to hold the dates from the text files. Initialize to null.
List<string> dateLinesWeek = null;
List<string> dateLinesMonth = null;
// this is the text file that contains the dates for week-end run dates.
dateLinesWeek = new List<string>() {
"1/1/2015",
"1/8/2015",
"1/15/2015",
"1/22/2015",
"1/29/2015"
};
dateLinesMonth= new List<string>()
{
"1/15/2015",
"2/15/2015",
"3/15/2015"
};
if (dateLinesMonth.Contains(today))
{
Console.WriteLine("Execute B");
}
else if(dateLinesWeek.Contains(today))
{
Console.WriteLine("Execute A");
}
You selected the batch-file tag in this question, so I posted a batch-file solution (that is much simpler than the C# one).
#echo off
setlocal
rem Get today's date and eliminate left zeros in each part
set today=%date:/0=/%
rem If there's a date in file A that's equal to today's date...
findstr /L "%today%" A.txt > NUL
if not errorlevel 1 (
rem then look at file B to see if today's date is contained in file B.
findstr /L "%today%" B.txt > NUL
rem If it is in file B...
if not errorlevel 1 (
rem run batch file "B"
call B.bat
) else (
rem run batch file "A"
call A.bat
)
)
rem If today's date is not listed in file A, do nothing

Console.Readline("") repeating at restart

I have this question,
My boss wants a program which you can enter a path, Console.ReadLine(directory);
This is irrelevant, I got this part working. In fact, the whole code/program is working as it should be.
The point of the path is that the program scans all the files in the given directory/subdirectories for the last write time. He want to pay minimum effort in this. So the plan is to use Windows to start this program once every 24 hours.
Only problem with this "minimum effort" part is that you have to enter the path EVERYTIME when it's started. So it actually doesn't go automaticly.
The question is: is there a way to avoid this?
For example Thread.Sleep(); and when it's done sleeping goto a label right under the Console.ReadLine(directory);?
So not once a day, but sleeping for 24 hours and for 1 whole minute working?
If it's any help, here's the code:
using System.IO;
using System.Security.Permissions;
namespace CheckWithinTime
{
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Which folder do you wish to scan?");
string path = Console.ReadLine();
//copies everything from the console to a .txt file
FileStream filestream = new FileStream(#"C:\Logs\Log.txt", FileMode.Create);
var streamwriter = new StreamWriter(filestream);
streamwriter.AutoFlush = true;
Console.SetOut(streamwriter);
Console.SetError(streamwriter);
//this is the path which you type in a the beginning of the program
string[] files = Directory.GetFiles(path, "*.*", System.IO.SearchOption.AllDirectories);
List<string> updatedFiles = new List<string>();
DateTime from = DateTime.Now.AddDays(-1);
DateTime to = DateTime.Now;
foreach (string name in files)
{
FileInfo file = new FileInfo(name);
string fullname = file.FullName;
//checks if the last writed time occured less then 24 hours ago, if it's not it will not be loggeed
if (file.LastWriteTime >= from && file.LastWriteTime <= to)
{
updatedFiles.Add(name);
Console.WriteLine(file.FullName + " ; " + "last changed at >> " + " ; " + file.LastWriteTime.ToString());
//Console.WriteLine("File created at >> " + file.CreationTime.ToString());
//Console.WriteLine("File last opened at >> " + file.LastAccessTime.ToString());
Console.WriteLine();
}
}
streamwriter.Close();
filestream.Close();
//The mail class basicly sends an e-mail to the server with the log file, but this is irrelevant
Mail();
}
}
}
It used to be just a simple file system watcher. After that it was like it is now, but without the Console.ReadLine() part. And now he wants to give a path.
If anyone can tell me a way to avoid the Console.ReadLine(), but only use call it when you need it. I would appreciate it!
Sorry in advance for my big texts.
The best way to do this would be to either create an XML file or use a notepad file and have windows run a task manager.
You can set up a program to run every so often in windows task manager and all you need to do is save the path to a file and have your C# console application read that file and get the path, the path will always be store and the program will run all the time.
We do this at work; a program has been running for 4 months doing through a bunch of paths and we don't edit it anymore.
Xml file/config is overkill for one setting. Pass it in to the command line string[] args:
string path;
if(args.Length > 0)
{
path = args[0];
Console.WriteLine("Using path: " + path);
}
else
{
Console.WriteLine("Which folder do you wish to scan?");
path = Console.ReadLine();
}
Then use task scheduler as already suggested, but pass the path as a command line argument. You can also then launch it with different paths without your app supporting multiple paths.

StreamWriter not writing data

I am using StraemWriter to log text messages to a log file. The log file should be created if it doesn't exist, appended to if the file creation date is less than a given time or recreated if created before that time. I am using the class/code below
public static class LogIt
{
private const string LOG_FNAME = #"Logfile.log";
public static void WriteMsg(string msg)
{
bool append = true;
if (File.Exists(LOG_FNAME))
{
//DateTime delDate = DateTime.Now.AddDays(-1);
DateTime delDate = DateTime.Now.AddMinutes(-30);
DateTime fileCreatedDate = File.GetCreationTime(LOG_FNAME);
if (DateTime.Compare(fileCreatedDate, delDate) < 0)
{
Console.WriteLine("DELETE FILE");
File.Delete(LOG_FNAME);
}
}
using (StreamWriter sw = new StreamWriter(LOG_FNAME, append))
{
sw.WriteLine(msg);
}
Console.WriteLine(msg);
}
}
This class is used by a simple console app run by the Task Scheduler which runs every x minutes.
The message are written as follows:
LogIt.WriteMsg("Log this message");
The messages are logged file when the file is initially created however when the file creation date is past the delete date, the file is recreated but no subsequent messages are ever written to the file.
Any ideas on why?
For some reason the file has the initial creation date (first time a file with that path ever created) as the creation date even if it is recreated after deleting. You can check the file properties and see that the log file creation date is always the same. A work around would be to update the file creation date in code whenever you recreate the file. You can use FileInfo class for that.
#MPD No problem. Here is the implementation of the workaround I suggested. Give it a try and let me know if that works.
private const string LOG_FNAME = #"Logfile.log";
public static void WriteMsg(string msg)
{
bool deleted = false;
bool append = true;
if (File.Exists(LOG_FNAME))
{
//DateTime delDate = DateTime.Now.AddDays(-1);
DateTime delDate = DateTime.Now.AddMinutes(-30);
DateTime fileCreatedDate = File.GetCreationTime(LOG_FNAME);
if (DateTime.Compare(fileCreatedDate, delDate) < 0)
{
Console.WriteLine("DELETE FILE");
File.Delete(LOG_FNAME);
//record that file was deleted and a new one will be created
deleted = true;
}
}
using (StreamWriter sw = new StreamWriter(LOG_FNAME, append))
{
sw.WriteLine(msg);
}
if (deleted)
{
//a new file is created. Make sure the creation time is set
FileInfo fi = new FileInfo(LOG_FNAME);
fi.CreationTime = DateTime.Now;
}
Console.WriteLine(msg);
}
I guess you are running this code on Windows 2003 (or maybe XP). If so: When you create a file in some directory at time T1 and the delete it and then re-create it; surprise surprise it has T1 as creation date!
I know this just because I had the same problem on Windows 2003!
BTW I use NLog now and (IMHO) it's perfect and has everything I need.

StreamWriter not updating its path on new day

I have a program that's writing to a log file called "appname_yyyyMMdd.log", where appname is the name of my app, and yyyyMMdd is the current date; a sample log file name might be "loglistener_20110615.log" . Anyway, my app creates the log file fine, and it updates it as planned. However, once the date changes, the app doesn't log anything, and it doesn't create a new file. In other words, since today is 6/15, I need it to create a file called "loglistener_20110616.log" after midnight tonight, and I need it to continue logging to that new file.
Here are code excerpts:
public static void LogInfo(string format, params object[] args)
{
lock (_logLock)
{
using (StreamWriter sw = File.AppendText(GetLogPath()))
{
sw.WriteLine(GetTimeStamp() + String.Format(format, args));
}
}
}
private static string GetLogPath()
{
string appName = "loglistener";
string today = DateTime.Today.ToString("yyyyMMdd");
string fileName = appName + "_" + today + ".log";
string fullLogPath = AppDomain.CurrentDomain.BaseDirectory + fileName;
return fullLogPath;
}
I checked this similar question, but that question describes a different scenario (with a non-applicable fix).
UPDATE - Just in case googlers land on this page, I later discovered a different cause altogether w/ this. My log is logging info from an email-listening service. The service itself had a problem where it was timing out after a half-hour. So, my problem wasn't w/ CreateText / AppendText... My problem was there was nothing to log. Very annoying, but I hope other people won't be misled by this question/answer.
You should check to make sure that the file exists first.
From the File.AppendText Documentation
Type: System.IO.StreamWriter A
StreamWriter that appends UTF-8
encoded text to an existing file.
public static void LogInfo(string format, params object[] args)
{
lock (_logLock)
{
using (StreamWriter sw = File.Exists(GetLogPath) ? File.AppendText(GetLogPath()) : File.CreateText(GetLogPath())
{
sw.WriteLine(GetTimeStamp() + String.Format(format, args));
}
}
}
Try that instead
After looking at the comments and re-reading the documentation.
File.AppendText
Should always work, regardless of file existence.

Categories