I have a little utility I'm writing that will let the user replace 1 character for another in a filename from a specific directory the user chooses.
The idea is to let the user replace an "_" or any other character they want with any other character they want or just remove it altogether.
EDIT: After taking the information I learned from your responses and a little Google searching to understand how those commands worked, I came up with this code. Any feedback would be nice.
private static void myremovechar()
{
//subprocedure to modify file names by removing or replacing characters NO SUB DIRECTORIES
//Ask user where the files are located and store value in string mybadfilesource
Console.Clear();
Console.WriteLine("Where are your files located");
Console.WriteLine(#"Example: D:\folder\subfolder\");
string mybadfilesource = Console.ReadLine();
//Ask user what character to remove and store value in string mychartodelete
Console.WriteLine("What character do you want to remove");
Console.WriteLine("Only 1 Character allowed");
string mychartodelete = Console.ReadLine();
//Ask user what character to replace mychartodelete with and store value in string mychartoreplace
//if user just hits enter, mychartodelete will just be deleted
Console.WriteLine("What character do you want to replace it with");
Console.WriteLine("Press enter to just delete previously selected Character");
Console.WriteLine("Only 1 Character allowed");
string mychartoreplace = Console.ReadLine();
try
{
//store list of files from mybadfilesource in var filelist
var filelist = Directory.EnumerateFiles(mybadfilesource);
foreach (string file in filelist)
{
//renames the files by Replacing mychartodelete with mychartoreplace
var newfile = string.Format("{0}{1}",Path.GetFileNameWithoutExtension(file).Replace(mychartodelete, mychartoreplace),Path.GetExtension(file));
File.Move(file, Path.Combine(mybadfilesource, newfile));
}
}
//Error Checking Process - Prints error message
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//tell user the process is done and return to Main Menu
Console.WriteLine("Finished - Press Enter to Return to Main Menu");
Console.ReadLine();
Console.Clear();
Main();
}
Thank you all for your help
There's a lot of wrong here:
You're calling Replace on the wrong variable
If you use the right variable, you'll still get an error for modifying a variable in a foreach loop
You're not really renaming anything, you're not applying anything back to the actual file.
try this:
foreach (var file in Directory.EnumerateFiles(mybadfilesource))
{
var newfile = string.Format("{0}{1}",
Path.GetFileNameWithoutExtension(file).Replace(mychartodelete, mychartoreplace),
Path.GetExtension(file));
File.Move(file, Path.Combine(mybadfilesource, newfile));
}
Be sure to just get the filename without the path or extension, or else you'd be changing those too
Related
I'm creating a simple C# program that automates editing different parts for a specific PHP file (for my work). But I have a problem. I'm working with multiple PHP files, all in different sub-folders, but with the same layout.
The program has access to all folders, and edits all the files at once. It stores the contents of each file in a List<string>. The main purpose of the program is to update a single string in each file, and then save the file. When this is done, I want Console to print out the single updated string in each file, and the path of the file with it. Here is this specific part of the program:
foreach(string item in paths)
{
if(File.Exists(item) == false) // checks if file exists
{
Console.WriteLine("Error!");
Console.WriteLine("File named " + Path.GetFileName(item) + " was not found.");
Console.WriteLine("Please confirm that you selected the right file.");
}
else
{
List<string> filecontents = File.ReadAllLines(item).ToList<string>();
for(int i = 0; i < filecontents.Count; i++)
{
if(!filecontents[i].StartsWith(#"//")) // checks to find right string to update
{
if(filecontents[i].Contains("http://") && !filecontents[i].Contains("https://")) // checks to find right string to update
{
string tempsubstring = filecontents[i].Substring(filecontents[i].IndexOf("http://") + 7, filecontents[i].IndexOf(#"/uadmin/gate.php") - (filecontents[i].IndexOf("http://")) - 7);
// extremely long code to extract substring where domainname needs to be filled in
filecontents[i].Replace(tempsubstring, domainname); // replace substring with own string
Console.WriteLine(filecontents[i]);
Console.WriteLine("Found at " + Path.GetFileName(Directory.GetParent(item).ToString())); // only prints name of parent file
Console.WriteLine();
}
}
}
}
}
This code seems fine to me at first, until I look at the outcome:
$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at *path of parent folder*
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]$real_home="http://test123/uadmin/gate.php";
Found at (path of parent folder)
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]
The program is working here, since I put "test123" in as the variable domainname. But ofcourse this string:
System.Collections.Generic.List`1[System.String]System.Collections.Generic.List`1[System.String]
Does not belong there.
Now, here's my question. Is this only when I print out that specific string from filecontents? or is it also stored in the list like that? Also, does anybody know why this happens, and how to remove it?
P.S: Converting the list to an array before printing also did not help.
I have a program that mass creates directories based on a CSV file. It runs through the loop but then it hits an "invalid characters in path" I need a validation (or if statement) to validate the folderName first and if it's invalid -reports it in a log file, then just proceed with the next folder creation.
StreamWriter sw = new StreamWriter(targetdir + "log.txt");
try
{
string[] items = File.ReadAllLines(csv);
foreach (string item in items)
{
Directory.CreateDirectory(targetdir + item);
sw.WriteLine(item + " OK!");
}
MessageBox.Show("Done");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
sw.Close();
I'm not sure where to start. I feel like i have to add an "if else" but i'm not sure what to put. Thanks in advance.
The main change you need to do in your code is stopping concatenating together the variables that creates the destination folder and start using the Path.Combine method.
In your specific case you could use GetInvalidFileNameChars to have a list of characters not allowed to be part of a path or file name and then check if the current item contains any of those characters.
But there are other important changes to do.
First a StreamWriter is a disposable object and thus you should always create it inside a using statement to have a correct cleaup of its internal resources when you have done with it or even if an abnormal exception occurs.
Second, it is better to use File.ReadLines instead of loading all the lines in memory with ReadAllLines
char[] invalidChars = Path.GetInvalidFileNameChars();
string logFile = Path.Combine(targetdir, "log.txt");
try
{
using(StreamWriter sw = new StreamWriter(logFile))
{
foreach (string item in File.ReadLines(csv))
{
if(item.Any(x => invalidChars.Contains(x)))
sw.WriteLine(item + " BAD");
else
{
Directory.CreateDirectory(Path.Combine(targetdir,item));
sw.WriteLine(item + " OK!");
}
}
}
MessageBox.Show("Done");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Finally, I want to underline that in this context it is important to use GetInvalidFileNameChars and not GetInvalidPathChars because here we are checking the name of a folder. This name has the same rules used for files.
GetInvalidPathChars omits some characters that are valid in a path string like the \ or the ? and *. So for example GetInvalidPathChars doesn't have any issues with something like C:\Windows\System32\*.dll while this string contains characters not usable for a filename or for a single folder's name.
The below is what I am wrestling with today using Visual Studios Console App.
What I want to happen, which currently isn't, is when the Console App opens, and I type the first "checksPath" in, if this turns out to not exist, I want it to say that the path is wrong, and either, let the user try again, or close the app. If the path is valid, then it moves onto the next "reportDest", and the same applies. If it's an invalid path, I want a message saying so, with the option of trying again, or closing the app. If both paths entered (eventually) are valid, I want a message to say that the report will now produce. The rest of the script that produces the report is perfectly fine, it's just the bit i've put below that's troublesome.
string checksPath;
Console.Write("Please enter the source path for the Checks Workbook, including the name of the file (Not including the file extension): ");
checksPath = Console.ReadLine() + ".xlsx";
try
{
if (File.Exists("checksPath"))
throw new FileNotFoundException();
}
catch (FileNotFoundException e)
{
Console.WriteLine("Invalid path - Please close the app and try again!");
Console.ReadLine();
}
string reportDest;
Console.Write("Please enter the folder location and file you wish your report to go to (Not including the file extension): ");
reportDest = Console.ReadLine() + ".xlsx";
try
{
if (File.Exists("reportDest"))
throw new FileNotFoundException();
}
catch (FileNotFoundException e)
{
Console.WriteLine("Invalid path - Please close the app and try again!");
Console.ReadLine();
}
Console.WriteLine("Your report will now produce");
Since you need to continually ask a question until the user gets it right, you will need a loop. Next in that loop you need to check if the path exists.
bool run = true;
while (run)
{
Console.Clear();
Console.WriteLine("Enter Path:");
string answer = Console.ReadLine();
if (Directory.Exists(answer)) run = false;
else
{
Console.WriteLine("Path Does not exists. Try again. Press enter to continue...");
Console.ReadLine();
}
}
I wrote this code, it works but there are 2 features I'd like to implement and I can't find out how.
First:
How to add an index number before each song so it looks like this:
Song1
Song2
Song3
Second:
The output to file includes the path to the file. How do I remove it?
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string[] files = Directory.GetFiles("E:\\Music", "*", SearchOption.AllDirectories);
foreach (string file in files)
{
string FileName = Path.GetFileName(file);
Console.WriteLine(FileName);
System.IO.File.WriteAllLines("E:\\songs.txt", (files));
}
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
}
}
So, in order to only write the name of the songs and not the whole path, you'll have to use Path.GetFileNameWithoutExtensions.
To write the index before every song, you'll have to switch to a for loop (to work with the index).
Another problem is that you're writing to songs.txt for every song, which is bad. Here's a code to help you out:
string[] files = Directory.GetFiles(#"C:\Users\Admin\Music\Playlists", "*", SearchOption.AllDirectories);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < files.Length; i++)
{
sb.AppendLine($"{i + 1}. {Path.GetFileNameWithoutExtension(files[i])}");
// Each line will be something like: Number. NameOfTheSong
}
// Only save to the file when everything is done
File.WriteAllText("E:\\songs.txt", sb.ToString());
Console.WriteLine("Press any key to exit");
Console.ReadLine();
First of all, I think that you have a problem with this line:
System.IO.File.WriteAllLines("E:\\songs.txt", (files));
Because in every loop you are writting the file songs.txt
About the new features:
For getting the index, an easy way is to change the foreach loop by a for loop.
For getting the file name you can use Path.GetFileName() or Path.GetFileNameWithoutExtension()
I hope this can help you.
I am writing a console application and I need to know, how to write in current line with shift of lines. I try to explain this on the next example:
Let It console lines with their numbers and contents along with cursor position.
Hello!
This is my command shell.
Please write something: _
When I call my method for writing in console text "lalala", i want to see that:
Hello!
This is my command shell.
lalala
Please write something: _
If I use Console.WriteLine method I see the next:
Hello!
This is my command shell.
Please write something: lalala
_
Please, help me to realise this feature.
Console.SetCursorPosition is the poison you are look for.
More details on http://msdn.microsoft.com/en-us/library/system.console.setcursorposition.aspx
As you didn't provide any code i assume you're using Console.WriteLine("Please write something"); to print out text. Since this will add an \n to the text you want to print you should rather use Console.Write("Please write something") then do an Console.ReadLine(); to get the input and handle the \n by yourself.
Console.WriteLine("1.Hello!");
Console.WriteLine("2.This is my command shell.");
Console.WriteLine("3.lalala");
Console.Write("4.Please write something:");
Console.Read();
If I understand your question right I think you need to use
Console.Write("text");
This will write on the same line as the cursor is currently on.
Rather than:
Console.WriteLine("text");
This will create a new line in the console each time it is called.
Please find the code for the above scenario:
private static void ReadAndWriteToConsole()
{
var mystrings = new List<string>();
mystrings.Add("Hello!");
mystrings.Add("This is my command shell.");
var input = WriteToConsole(mystrings);
while (input.ToLower() != "exit")
{
mystrings.Add(input);
Console.Clear();
input = WriteToConsole(mystrings);
}
}
private static string WriteToConsole(IEnumerable<string> variables )
{
foreach (var str in variables)
{
Console.WriteLine(str);
}
Console.Write("Please write something:");
return Console.ReadLine();
}
Hope that helps.
NOTE: If you want the number of each string then use a for loop instead of foreach and just print the variable used in the console.writeline.
try something like this
Console.Write("Hello\nThis is My Command Shell\nlalala\nPlease Enter Something:___");
if course that would end up having them all appear at the same time, but if your good with that this will work
Will look like this
I realize that this is an old question, however I have been searching this stuff and here is how it can be coded:
Console.WriteLine("Hello!");
Console.WriteLine("This is my command shell.");
string text = "";
string toWrite = "Please write something: ";
while (text != "quit")
{
Console.Write(toWrite);
text = Console.ReadLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
Console.WriteLine(text.PadRight(text.Length + toWrite.Length));
}
The Console.SetCursorPosition puts the cursor back to the line that was written into, then overwrite what is written with the text and a padding equivalent to how many chars the text had.