How to get an incremented value to keep its count - c#

The way my code is currently written, it will change the name of a file to the current date and then it will move it to a completed folder in the sub directory. That all works fine.
What I'm trying to implement is being able to rename it with different numbers as well if there are duplicates. Basically, if the file already exists in the completed folder, it will rename it "the date"(1).csv.
My issue is that because i is set to 1, even though I increment i, it resets it back to 1. I just want it to hold the incremented value while the code is running. if there are three files in the folder it retrieves it from, I want it to label them "the date", "the date"(1), and "the date"(2). Then if the code runs again tomorrow it will start the count over. Most likely my code will never experience more than one file in the folder. I want to implement this as a safety. If for whatever reason there is more than one file in the folder I want my code to be able to still run.
This is what I have so far:
int i = 1;
var newFileName = DateTime.Now.ToString("MMddyyyy") + ".csv";
destinationPath = Path.Combine(GenesisDirectory, "Completed");
Directory.CreateDirectory(destinationPath);
var destinationFileName = Path.GetFileName(newFileName);
destinationPath = Path.Combine(destinationPath, destinationFileName);
if (File.Exists(destinationPath))
{
newFileName = DateTime.Now.ToString("MMddyyyy") + "(" + i + ")" + ".csv";
destinationFileName = Path.GetFileName(newFileName);
var Dironly = Path.GetDirectoryName(destinationPath);
destinationPath = Path.Combine(Dironly, destinationFileName);
i++;
}
File.Move(inputFile, destinationPath);

You might want to make your counter static so it persists across calls. You will need to move it out of any method it is in to do that. There are better ways to do it, but you've somewhat limited the scope of solutions by not providing more of your code.

private static int s_Counter = 1;
public static IncrementCounter () { Interlocked.Increment(ref s_Counter); }
public static int Counter { get { return s_Counter; } }
We use Interlocked.Increment instead of s_Counter += 1 in case you later decide to make your code multi-threaded. (As a rule, static methods/properties should be designed to be thread safe.)

You could just make it as static to make the value persist across the call,but the counter value will reset if you restart your application that will result in some undesirable behaviour.
The best practice is to store your counter value in a database or a file so that even after restarting your application you can access the updated counter value and your code will correctly.

Related

Store multiple int in a .txt file, each time on a new line

Sorry for the bad title, i didn't know how to explain it better. I just started in Csharp so its probably a dumb mistake.
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = "CPU Usage" + " " + (int)cpuCounter.NextValue() + "%";
string[] usageCPUay = { label1.Text };
System.IO.File.WriteAllLines(#"C:\Users\Filip\Desktop\CPUOutput.txt", usageCPUay);
}
So this is the code I have issues with and can't understand how to fix it. I tried with streamwriter but I got the same issues. I want to make the output the cpuCounter gives to store in a txt file. But every time it just writes the latest CPU Usage and not every one. Like this wrong output. I want it to type all the cpu usages it got and store them like that but every new one in a separate line.
Let's analyze your code:
you have a method, in the body you have label1.text which is text I assume, a string.
then you have got an array of strings, but this array contains only a single element, which is label1.text, then you write in the text file the array, which contains only a single element.
3 errors I see:
1.- the array contains a single element, therefore you are only storing a single line.
2.- at the end of the string that you are meant to record in the text file you should add "\n" for a new line.
3.- I understand from https://learn.microsoft.com/en-us/dotnet/api/system.io.file.writealllines?view=netcore-3.1#System_IO_File_WriteAllLines_System_String_System_String___ that it creates the file as new, therefore you may be deleting what you already have.
Solution:
Like in the example that was presented to you in the link, I would do the following:
label1.Text = "CPU Usage" + " " + (int)cpuCounter.NextValue() + "%\n";
string[] usageCPUay = { label1.Text };
if (!File.Exists(path))
{
// Create a file to write to.
File.WriteAllLines(path, usageCPUay);
}
else{
File.AppendAllText(path, usageCPUay);}

CreatDirectory or Delete directory is slower than code

Just a quick question if you can help me, please.
In C#, I am creating a directory, if it does not exist. In the next command, I am checking if the directory exists, I will copy some files.
The Problem is, to creating a new directory or Deleting it, takes time and slower than next code execution time.
The software gives an error of "The folder does not exist ".
I used Thread.Sleep(5000); to wait 5 seconds before copying the content to the directory.
It seems to be working but I feel like that this is not how it's supposed to be done. Does anyone know better coding?
string logDirectoryPath = Directory.GetCurrentDirectory() + "\\LogFiles";
if (!Directory.Exists(logDirectoryPath))
{
Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\LogFiles");
Thread.Sleep(5000);
}
if (Directory.Exists(Directory.GetCurrentDirectory() + "\\LogFiles"))
{
var s = logDirectoryPath + "\\Log_" + DateTime.Now.ToString("dd_MM_yyyy") + ".txt";
using (StreamWriter w = File.AppendText(s))
{
w.WriteLine("--");
w.Write("\r\nLog Entry : ");
w.WriteLine($"{DateTime.Now.ToLongTimeString()} {DateTime.Now.ToLongDateString()}");
}
}
//EDIT
JUST thought maybe I should use a loop?
While(!Directory.Exists(logDirectoryPath))
{
Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\LogFiles");
}
Use DirectoryInfo
DirectoryInfo di = new DirectoryInfo(#{PATHSTRING});
and use di.Exists to check it exists / di.Create() to create folder
and I'd like to recommend to use logDirectoryPath which you defined already.
like this
DirectoryInfo di = new DirectoryInfo(logDirectoryPath);
if ( !di.Exists ) {
di.Create();
}

Apply Folder Icon Change

I am attempting to change the icon of a folder. The code below does all what I found online says to do but the icon never changes. Am I maybe not "Applying" the change?
string createdFile = Path.Combine(#"C:\Users\np\Desktop\PUTEST", "desktop.ini");
if (File.Exists(createdFile))
{
var di = new DirectoryInfo(createdFile);
di.Attributes &= ~FileAttributes.ReadOnly;
File.Delete(createdFile);
File.Create(createdFile).Dispose();
}
else
{
File.Create(createdFile).Dispose();
}
//string iconPath = #"%SystemRoot%\system32\SHELL32.dll";
string iconPath = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\SHELL32.dll");
string iconIndex = "-183";
using (TextWriter tw = new StreamWriter(createdFile))
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
File.SetAttributes(createdFile, System.IO.FileAttributes.ReadOnly);
File.SetAttributes(createdFile, System.IO.FileAttributes.System);
File.SetAttributes(createdFile, System.IO.FileAttributes.Hidden);
When crafting a file like this it's always good to do so using Explorer or Notepad first, then write/adjust your code to match whatever was produced. Otherwise, it's harder to figure out if the problem is with your file or your code.
I believe the minimum requirements to make this work is Desktop.ini must be marked System and the parent directory must be marked ReadOnly (System may work there as well, but I know ReadOnly definitely does). So, your code is working with the right attributes, but there are still a few problems.
Your if ... else ... block is saying "If a file exists at this path, create a directory at that path, then delete the file at that path, then create a file at that path." Of course, the directory should not and cannot have the same path as the file. I assume you are deleting and recreating the file to clear the contents when it already exists, however File.Create() overwrites (truncates) existing files, making the calls to both File.Delete() and File.Exists() unnecessary.
More importantly is this line...
di.Attributes &= ~FileAttributes.ReadOnly;
...with which there are two problems. First, you are ANDing the directory's attributes with the negation of ReadOnly, which has the effect of removing ReadOnly and keeping the other attributes the same. You want to ensure ReadOnly is set on the directory, so you want to do the opposite of the code you used: OR the directory's attributes with ReadOnly (not negated)...
di.Attributes |= FileAttributes.ReadOnly;
Also, you need that attribute set regardless of whether you created the directory or not, so that line should be moved outside of the if ... else ....
Another issue is the successive calls to File.SetAttributes(). After those three calls the file's attributes will be only Hidden, since that was the value of the last call. Instead, you need to combine (bitwise OR) those attributes in a single call.
A couple of other minor tweaks...
As you know since you are calling Dispose() on it, File.Create() returns a FileStream to that file. Instead of throwing it away, you could use it to create your StreamWriter, which will have to create one, anyways, under the covers. Better yet, call File.CreateText() instead and it will create the StreamWriter for you.
Environment variables are supported in Desktop.ini files, so you don't have to expand them yourself. This would make the file portable between systems if, say, you copied it from one system to another, or the directory is on a network share accessed by multiple systems with different %SystemRoot% values.
Incorporating all of the above changes your code becomes...
// Create a new directory, or get the existing one if it exists
DirectoryInfo directory = Directory.CreateDirectory(#"C:\Users\np\Desktop\PUTEST");
directory.Attributes |= FileAttributes.ReadOnly;
string filePath = Path.Combine(directory.FullName, "desktop.ini");
string iconPath = #"%SystemRoot%\system32\SHELL32.dll";
string iconIndex = "-183";
using (TextWriter tw = File.CreateText(filePath))
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
File.SetAttributes(filePath, FileAttributes.ReadOnly | FileAttributes.System | FileAttributes.Hidden);
One catch is that the above code throws an exception if you run it twice in succession. This is because the File.Create*() methods fail if the input file is Hidden or ReadOnly. We could use new FileStream() as an alternative, but that still throws an exception if the file is ReadOnly. Instead, we'll just have to remove those attributes from any existing input file before opening it...
// Create a new directory, or get the existing one if it exists
DirectoryInfo directory = Directory.CreateDirectory(#"C:\Users\np\Desktop\PUTEST");
directory.Attributes |= FileAttributes.ReadOnly;
string filePath = Path.Combine(directory.FullName, "desktop.ini");
FileInfo file = new FileInfo(filePath);
try
{
// Remove the Hidden and ReadOnly attributes so file.Create*() will succeed
file.Attributes = FileAttributes.Normal;
}
catch (FileNotFoundException)
{
// The file does not yet exist; no extra handling needed
}
string iconPath = #"%SystemRoot%\system32\SHELL32.dll";
string iconIndex = "-183";
using (TextWriter tw = file.CreateText())
{
tw.WriteLine("[.ShellClassInfo]");
tw.WriteLine("IconResource=" + iconPath + "," + iconIndex);
//tw.WriteLine("IconFile=" + iconPath);
//tw.WriteLine("IconIndex=" + iconIndex);
}
file.Attributes = FileAttributes.ReadOnly | FileAttributes.System | FileAttributes.Hidden;
I changed from using File to FileInfo since that makes this a little easier.

Got stuck thinking in an idea that i got

First of all, sorry that I was unable to give a proper title.
I got stuck with an idea that's been with me today almost the whole day after searching and searching and searching, till it came to a point that I decided to ask it on Stackoverflow!
So here's where I am stuck:
(I am making an auto-installer currently coded in C# and it is Dutch. It works really awesome but I just need one thing to finish my base. For example:
You have 'multiple' objects selected in a checklistbox, those are read from the checklistbox itself, they get trimmed and they get launched after that.
Now that's all working, I wanted to add a waiting method, for example we got:
Malwarebytes & CCleaner as installation 'example'.
Now when both are checked, and I click start, it starts both of the programs.
What I want to do is: to tell the program to start one program, do your thing, once its finished (closed) it should go to the next.
But... There is a problem, my programs are started in an array, so it basically works if there are multiple objects checked, than it will start all of the checked objects. And I really have no idea how to reach the same thing which is basically :
If there are multiple objects selected, start the object(s), do your thing(auto-clicking etc.),once its closed and confirmed its closed, move on to the next object and do the same thing until its been completed. I would like to make it work with a progressbar, but never really looked into a progress bar as they seem confusing.
I have a piece of code that finds the Process ID so maybe I can do something with that, but the Process ID is never the same on the applications that I start, so when they start in an array I got kinda of an issue.
Could someone help me please figuring out what & how to code / do this?
here's the code i use to make this work :
string pad = Application.StartupPath;
foreach (string checkedItem in checkedListBox1.CheckedItems)
{
if (checkedItem.Contains("."))
{
string str = checkedItem;
if (str.Contains("."))
{
int index = str.IndexOf('.');
string folder = str.Substring(0, index);
try
{
bool started = false;
var process = new Process();
process.StartInfo.FileName = pad + "/data/" + folder + "/" + checkedItem;
started = process.Start();
var processID = process.Id;
var processNAAM = process.ProcessName;
textBox1.Text += "Gevonden - ID: " + processID + " NAAM: " + processNAAM + Environment.NewLine;
textBox1.Text += DateTime.Now.ToString("HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo) + " - " + "Installatie Keuze wordt opgestart." + Environment.NewLine;
process.WaitForExit();
}
catch (Exception)
{
}
}
}
}
First of all, you can make the code simpler and shorter by using the CheckedListBox's CheckedItems property. Secondly, there's no point to all your copying of strings from one to another. Strings are immutable in .NET - they never change. You can keep just one copy and cut from there.
Next, you can use the methods in System.IO.Path to cut the filename without the extension, or to build a full path without worrying about having too many or too few "/"'s.
Third, for your original question - just call WaitForExit on your Process object to make it wait before moving on with the list of processes.
Thirdly
foreach (string checkedItem in checkedListBox1.CheckedItems)
{
if (checkedItem.Contains("."))
{
string baseName = Path.GetFileNameWithoutExtension(checkedItem);
string processPath = Path.Combine(pad, "data", baseName, checkedItem);
Process process = Process.Start(processPath);
process.WaitForExit();
}
}
After the line where you start the process (process.Start()), simply add the following:
process.WaitForExit()
This will pause the containing thread until the target process has exited.

File is not created after another has been created

I am trying to create 2 XML files in the same folder.
For some reason it does create the first one, but does not create the second one.
Could it be that the first one is still being created when an attempt to create the second file is made, and therefore the latter fails?
I don't get any errors with the code:
if (File.Exists(FileNameTextBox.Text + ".AA.xml"))
{
MessageBox.Show("Already exists. renaming to *.old" + Environment.NewLine +
"if there is already an *.old file, this will be deleted.");
if (File.Exists(FileNameTextBox.Text + ".AA.xml.old"))
{
File.Delete(FileNameTextBox.Text + ".AA.xml.old");
}
File.Move(FileNameTextBox.Text + ".AA.xml", FileNameTextBox.Text + ".AA.xml.old");
}
if (!File.Exists(FileNameTextBox.Text + ".AA.xml"))
{
XmlTextWriter textWritter = new XmlTextWriter(FileNameTextBox.Text + ".AA.xml", null);
textWritter.WriteStartDocument();
textWritter.WriteStartElement("Data");
textWritter.WriteEndElement();
textWritter.Close();
}
if (File.Exists("BB.xml"))
{
if (File.Exists("BB.xml.old"))
{
File.Delete("BB.xml.old");
}
File.Move("BB.xml", "BB.xml.old");
}
if (!File.Exists("BB.xml"))
{
XmlTextWriter textWritterPC3 = new XmlTextWriter("BB.xml", null);
textWritterPC3.WriteStartDocument();
textWritterPC3.WriteStartElement("Data");
textWritterPC3.WriteEndElement();
textWritterPC3.Close();
}
Whats in FileNameTextBox.Text? Does it specify a directory path?
Your second file is created without saying which directory. So it will be created in the current directory - which is not necessarily the directory specified by FileNameTextBox.Text
You are not specifying an absolute path for your file names, so you are using whatever the current directory happens to be, which is not reliable. Also you may need to call DirectoryInfo.Refresh() or FileInfo.Refresh() to make sure you are seeing the latest directory information (whether the file exists or not).
The comment is only making the last if case execute the first row.. The last if should look like this. I don't know if it's only in your example.
Your example
if (!File.Exists("BB.xml")) // {
XmlTextWriter textWritterPC3 = new XmlTextWriter("BB.xml", null);
should be
if (!File.Exists("BB.xml")) //
{
XmlTextWriter textWritterPC3 = new XmlTextWriter("BB.xml", null);
textWritterPC3.WriteStartDocument();
textWritterPC3.WriteStartElement("Data");
textWritterPC3.WriteEndElement();
textWritterPC3.Close();
}

Categories