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

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

Related

Strange behavior on Windows setting file creation time

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.

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));

Compare subfolders name

I'm not sure what the correct question for my case would be but I'll try to describe as good as I can. I have to mention that I don't have much knowledge of this language, I'm using it strictly for the executable of my appplication, mainly I mess around with Java. So I have an app that only starts up if it finds java in my PC. I'm using something like this:
ProcessStartInfo startJava = new ProcessStartInfo("java", JavaProcessArguments());
startJava.CreateNoWindow = !client.ShowConsole;
startJava.UseShellExecute = false;
But, let's say I want to use openJDK, then I would have to change "java" to something like this:
ProcessStartInfo startJava = new ProcessStartInfo
(#"C:\Program Files (x86)\Java\openJDK_1.7\bin\java.exe", JavaProcessArguments());
Moving on, I wanted to start openJDK FIRST, even if java is present, so I wrote a condition that does that:
private void StartTheProcess()
{
string pathJDK = #"C:\Program Files (x86)\Java\openJDK_1.7\bin\";
bool isDirJDK7 = Directory.Exists(pathJDK);
if (isDirJDK7)
{
ProcessStartInfo startJava = new ProcessStartInfo(#"C:\Program Files (x86)\Java\openJDK_1.7\bin\java.exe", JavaProcessArguments());
startJava.CreateNoWindow = !client.ShowConsole;
startJava.UseShellExecute = false;
try
{
using (Process p = Process.Start(startJava))
{
p.WaitForExit();
}
}
catch (Win32Exception ex)
{
some error...
}
catch (Exception e)
{
some error...
}
}
else
{
ProcessStartInfo startJava = new ProcessStartInfo("java", JavaProcessArguments());
startJava.CreateNoWindow = !client.ShowConsole;
startJava.UseShellExecute = false;
try
{
using (Process p = Process.Start(startJava))
{
p.WaitForExit();
}
}
catch (Win32Exception ex)
{
some error...
}
catch (Exception e)
{
some error...
}
}
}
Now let's suppose I have more openJDK versions in the "C:\Program Files (x86)\Java\" folder: openJDK_1.7, openJDK_1.7_u1, openJDK_1.8, so on, and I want to start the latest one. How should I accomplish this? I think one method would be to compare the subfolders names found there but I don't really know how to. The content of all the subfolders is identical and the names of the subfolders have the same construction (openJDK_1.X / openJDK_1.X_uYZ). Could you help me, based on this poorly (most likely) code? :D
There are a few things you could try,
Split the directory name string by
var version = string.split('_'), and then the version would be version[1] = "1.7", you can convert all of these into doubles/decimals/floats,etc and just sort the data out, get the latest version (the one with the highest number and get its directory back
The second thing you can try is checking the Directory.GetLastWriteTime(String), which you can compare, and find the last one, please not that this is not reliable at all since the folder can be changed by anything.

Moving oldest folder based on name (YYYYMMDD)

I have a directory of around 30-40 folders that contain various backup files for a CRM system.
I have developed a script that downloads the files from a remote server, and places them in folders with YYYYMMDD, however due to space restrictions I now need to move the oldest folder from the directory. As the IT team at the company keep moving the folders between servers I cannot use the folder creation date!
What is the easiest option? I have looked at: deleting the oldest folder by identifying from the folder name and attempted to order the items then perform a move.
My other option was to take all of the folder names in the root directory, parse into a list of type time and date, select the lowest (oldest) option, then perform the file move?
how about something like this:
bool MoveOldestFolder(string initialFolderName, string destinationFolder)
{
// gets all top folders in your chosen location
var directories = System.IO.Directory.EnumerateDirectories(initialFolderName,"*", System.IO.SearchOption.TopDirectoryOnly);
// stores the oldest folder and it's date at the end of algorithm
DateTime outDate;
DateTime oldestDate = DateTime.MaxValue;
string resultFolder = string.Empty;
// just a temp variable
string tmp;
// using LINQ
directories.ToList().ForEach(p =>
{
tmp = new System.IO.FileInfo(p).Name; // get the name of the current folder
if (DateTime.TryParseExact(tmp,
"yyyyMMdd", // this is case sensitive!
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out outDate)) // try using folder name as date that "should" be in yyyyMMdd format - if the conversion is successful and date is older than current outDate, then store folder name and date, else nothing
{
if (outDate.Date < oldestDate.Date)
{
oldestDate = outDate;
resultFolder = p;
}
}
});
// if we actually found a folder that is formatted in yyyyMMdd format
if (!oldestDate.Equals(DateTime.MaxValue))
{
try
{
System.IO.Directory.Move(resultFolder, destinationFolder);
return true;
}
catch(Exception ex)
{
// handle the excaption
return false;
}
}
else
{
// we didnt find anything
return false;
}
}
private void button1_Click(object sender, EventArgs e)
{
var initialFolderName = #"C:\initial";
var destinationFolder = #"c:\dest";
if (MoveOldestFolder(initialFolderName, destinationFolder))
{
// move was successful
}
else
{
// something went wrong
}
}
Other option would be to simply do what chrfin said but I wouldn't presume on everything being "dandy" in the folder structure. There is always a possibility that the folder name is not in YYYYMMDD format and that would probably cause some problems I imagine.
Anyway, the code could look something like this:
var directories = System.IO.Directory.EnumerateDirectories(initialFolderName,"*", System.IO.SearchOption.TopDirectoryOnly);
directories.ToList<string>().Sort();
var lastDir = directories.First();

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.

Categories