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.
Related
Hi I have a code that you can save file and give specific file naming.
the problem is how can I check if file exist in the folder directory.
What I'm trying to do is like this.
FileInfo fileInfo = new FileInfo(oldPath);
if (fileInfo.Exists)
{
if (!Directory.Exists(newPath))
{
Directory.CreateDirectory(newPath);
}
fileInfo.MoveTo(string.Format("{0}{1}{2}", newPath, extBox1t.Text + "_" + textBox2.Text + "_" + textBox3.Text, fileInfo.Extension));
im trying to add MessageBox.Show in the below
if (!Directory.Exists(newPath))
{
MessageBox.Show("File Exist. Please Rename!");
Directory.CreateDirectory(newPath);
But it does not work. Or is there a way to add extension name at the last part of filename it should like this
Example: STACKOVERFLOWDOTCOME_IDNUM_11162022_0
if STACKOVERFLOWDOTCOME_IDNUM_11162022 exist it will rename to STACKOVERFLOWDOTCOME_IDNUM_11162022_0
it will add _0 at the last part.
One way to do it is to write a method that extracts the directory path, name, and extension of the file from a string that represents the full file path. Then we can create another variable to act as the "counter", which we'll use to add the number at the end of the file name (before the extension). We can then create a loop that checks if the file exists, and if it doesn't we'll increment the counter, insert it into the name, and try again.
For example:
public static string GetUniqueFileName(string fileFullName)
{
var path = Path.GetDirectoryName(fileFullName);
var name = Path.GetFileNameWithoutExtension(fileFullName);
var ext = Path.GetExtension(fileFullName);
var counter = 0;
// Keep appending a new number to the end of the file name until it's unique
while(File.Exists(fileFullName))
{
// Since the file name exists, insert an underscore and number
// just before the file extension for the next iteration
fileFullName = Path.Combine(path, $"{name}_{counter++}{ext}");
}
return fileFullName;
}
To test it out, I created a file at c:\temp\temp.txt. After running the program with this file path, it came up with a new file name: c:\temp\temp_0.txt
I have the following code to rename files in the following tree as from 00000001.pdf to the last file with this 8 character left padding, e.g: 00000100.pdf
Folder1
subfolder1
childfolder1
pdffile1
pdffile2
childfolder2
pdffile3
pdffile4
subfolder2
childfolder3
pdffile5
pdffile6
But for some reason in some of those child folders it keeps renaming them with no end.
Some times it just jumps to another number, as if it was an async operation. But if I stop and start again it goes okay until the second next folder, when it messes up again.
But this error only happened within 19 folders.
Indeed their pdf names are different from the others, but I don't see how it is related.
The other files were named something like "DOCUMENT_01" and so on, but these are:
0000000100000001.pdf
0000000200000001.pdf
0000000300000001.pdf
etc
static void Main(string[] args)
{
Console.WriteLine("Digite a pasta 'pai' onde serão buscados pdfs dentro das pastas 'filhas':");
string path = Console.ReadLine();
foreach (string dir in Directory.EnumerateDirectories(path))
{
foreach (string subdir in Directory.EnumerateDirectories(dir))
{
Console.WriteLine($"{dir} - {subdir}");
int n = 1;
foreach (string pdffile in Directory.EnumerateFiles(subdir, "*.pdf", SearchOption.AllDirectories))
{
Console.WriteLine(n.ToString().PadLeft(8, '0') + " " + new FileInfo(pdffile).Length);
File.Move(pdffile, subdir + $"\\{n.ToString().PadLeft(8, '0')}.pdf");
n++;
}
Console.WriteLine("\n\n");
}
}
}
What could be going wrong?
It should await for the File.Move method to end to add the n + 1 and then moving to the next pdffile as a synchronous operation. So why does it jumps numbers after a random time and why it keeps going forever other times?
And just to remember, if I stop the program and start again and put the folder that was messed up as the first one, it goes ok and only when it goes to the next folder, or the folder after next that it start to give me this error again.
Hope that I could make myself clear... Thanks for your attention!
EDIT: will try using FileInfo class to give me the parent folder with the SearchOption.AllDirectories option and exclude this 3 stage loop plus actually working for any kind of tree structure
EDIT2: Tried, worked as a "tree indepent" script but getting the same result with the files name after the first folder... As it's really fast, in 3 seconds it goes from 00000169.pdf to 00006239.pdf in a folder with just 330 items.
As commented already, it is not a good idea to move or rename files “WHILE” the code is enumerating though the list of those files as the posted code appears to do. This will cause obvious problems and you should simply mark the files somehow, then later come back and rename or move them.
More importantly, the big issue related to renaming/moving files is exactly as you describe with your current issue. The problem is that the errors are erratic and not consistent. Making it very difficult to trace. However, the problems you describe are classic trademarks of moving/renaming files while enumerating through those files.
With that said, the best way and easiest way to traverse an unknown number of folder levels given a starting folder is by using recursion. In a lot of cases, recursion can be avoided with some well though out loops, however when we do not know how many levels of folders there are, then, using a simple loop or foreach loop paradigm may be doable, however, you will most likely be adding variables and code that only makes this more complex. This is shown in the current code with the addition of the dir variable to keep track of “when” a different folder is used. Recursion is suited ideally for this situation.
In this case, this recursive method will be called ONCE for each folder and subfolders from a given “starting” folder location. This means that each time this recursive method is called is when a different folder is beginning to be processed. So n would always start at 1 and we do not need to keep track of the current folders path.
So the signature of this method will take a DirectoryFolder object as a “starting” folder. First we create some variables; a FileInfo array pdffiles to hold the pdf files in the given folder; in addition to a DirectoryInfo array foldersInThisFolder to hold all the other folders in this starting folder. Lastly an int n to index the files as the posted code is doing.
Next we get all the pdf files in this “starting” folder. If there are pdf files in this folder, then we loop through those files and process them. Next, we get all the other folders in this “starting” folder. Then start a loop through each folder. For each folder in this collection we will make the recursive call back to this method using the next folder as the “starting” folder, then the whole process continues until the loop through those folders ends.
static void TraverseDirectoryTree(DirectoryInfo startingFolder) {
FileInfo[] pdffiles = null;
DirectoryInfo[] foldersInThisFolder = null;
int n = 1;
Console.WriteLine(startingFolder.FullName);
// get all the pdf files in this folder
try {
pdffiles = startingFolder.GetFiles("*.pdf");
}
catch (Exception e) {
// you may want to catch specific exceptions
// however in this example we do not care what
// the exception is, we will simply ignore this.
// in most cases pdffiles will be null if an exception is thrown
Console.WriteLine(e.Message);
}
if (pdffiles != null) {
foreach (FileInfo pdffile in pdffiles) {
Console.WriteLine(pdffile.FullName + " -> " + n.ToString().PadLeft(8, '0') + " " + pdffile.Length);
//File.Move(pdffile.FullName, pdffile.DirectoryName + $"\\{n.ToString().PadLeft(8, '0')}.pdf");
// add file path to a list of files to rename later?
n++;
}
// start over wiith the sub folders in this folder
foldersInThisFolder = startingFolder.GetDirectories();
foreach (DirectoryInfo dirInfo in foldersInThisFolder) {
TraverseDirectoryTree(dirInfo);
}
}
}
Usage…
Console.WriteLine("Type the folder you want to start with:");
string path = Console.ReadLine();
DirectoryInfo di = new DirectoryInfo(path);
TraverseDirectoryTree(di);
Edit… after further testing it appears that what you are wanting to do is simply “rename” the pdf files. As suggested a simple solution is to save the files that we want to rename, then, after we collect the files we want to rename, we simply loop through those files and rename them. This should eliminate any problems by renaming files while enumerating though the files collection.
To help, I created a Dictionary<string, int> called filesToRename. While recursively looping through all the folders, we will add the full path of each pdf file we want to rename as the Key and the int value n as the Value. After the dictionary is filled we would simply loop through it and rename the files.
private static Dictionary<string, int> filesToRename = new Dictionary<string, int>();
Then replace the commented-out line in the recursive method TraverseDirectoryTree…
//File.Move(pdffile.FullName, pdffile.DirectoryName + $"\\{n.ToString().PadLeft(8, '0')}.pdf");
With…
filesToRename.Add(pdffile.FullName, n);
Then after the dictionary is filled we would loop through it and rename the files, something like…
DirectoryInfo di = new DirectoryInfo(path);
TraverseDirectoryTree(di);
foreach (KeyValuePair<string, int> kvp in filesToRename) {
int index = kvp.Key.ToString().LastIndexOf(#"\");
string dir = kvp.Key.ToString().Substring(0, index);
File.Move(kvp.Key, dir + $"\\{kvp.Value.ToString().PadLeft(8, '0')}.pdf");
}
I am hoping this makes sense…
Answer as Klaus Gütter helped me, I just added .ToList() to the Directory.EnumerateFiles so it made a fixed list first, and then made the foreach for each file
It will rename every pdf within the folder and it's subfolders
Console.WriteLine("Type the folder you want to start with:");
string path = Console.ReadLine();
string dir = "";
int n = 1;
foreach (string pdffile in Directory.EnumerateFiles(path, "*.pdf", SearchOption.AllDirectories).ToList())
{
FileInfo fi = new FileInfo(pdffile);
if (fi.DirectoryName == dir)
{
Console.WriteLine("\t" + n.ToString().PadLeft(8, '0'));
File.Move(pdffile, dir + $"\\{n.ToString().PadLeft(8, '0')}.pdf");
n++;
}
else
{
n = 1;
dir = fi.DirectoryName;
Console.WriteLine("\n\n" + dir);
File.Move(pdffile, dir + $"\\{n.ToString().PadLeft(8, '0')}.pdf");
Console.WriteLine("\t" + n.ToString().PadLeft(8, '0'));
n++;
}
}
I have to copy a certain file to another folder, and this has to happen when I click a button.
Now I have two problems: the file is not copied correctly, and the new folder with the new file is created after one or two minutes.
When i say copied incorrectly, I mean that -0.364384 becomes -0.365163223838319.
I'm currently using this script in my button (ps I have three buttons for files named 1.json 2.json and 3.json)
private string path = "Assets\\Modelli\\Sinc ";
public void salvaEs1()
{
if (Directory.Exists(path)) { Directory.Delete(path, true); }
Directory.CreateDirectory(path);
string fileToCopy = "Assets\\Modelli\\daMedico\\1.json";
string destinationDirectory = "Assets\\Modelli\\Sinc\\";
File.Copy(fileToCopy, destinationDirectory + "sinc.json");
}
Errors are about some code that I use to read the file. But the problem are the errors in the file, non the ones that come from them
I have a question. I want to copy specific files in 'New folder' to 'Target' folder by clicking a button. In 'New folder' contains various of file with different name. For example: "abcUCU0001", "abbUCA0003", "hhhUCU0012", "aaaUCS0012" and many more. 'New folder' contains more than 1000 files and have same 10 letters in its name. I want to copy 10 files and its name must have "UCU". I don't know how to copy using (startsWith) starting with 4th letter.
Sorry for my bad grammar.
private void button1_Click(object sender, EventArgs e)
{
string FROM_DIR = #"C:\Users\Desktop\Source";
string TO_DIR = #"C:\Users\Desktop\Target";
DirectoryInfo diCopyForm = new DirectoryInfo(FROM_DIR);
DirectoryInfo[] fiDiskfiles = diCopyForm.GetDirectories();
string filename = "UCU";
int count = 0;
foreach (DirectoryInfo newfile in fiDiskfiles)
{
try
{
if (newfile.Name=="New folder")
{
foreach (FileInfo file in newfile.GetFiles())
{
if(file.FullName.StartsWith(filename))
{
File.Copy(file.FullName, Path.Combine(TO_DIR,file.Name));
count++;
if (count == 10)
{
break;
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
MessageBox.Show("success");
}
I expect after click a button, 10 files with name "UCU" will copied to Target folder.
If all the files are in the same directory (no sub-directories), then you can get all files using:
//assuming diCopyForm is the new folder reference
// ? denotes 1 character while * is multiple chars
var files = diCopyForm.GetFiles("???UCU*");
And then just copy them across. For more complex criteria, I would get all the files and use LINQ to filter through.
Details about the search pattern used
If there are a lot of files in the folder then it might be more efficient to use the EnumerateFiles method
The EnumerateFiles and GetFiles methods differ as follows: When you
use EnumerateFiles, you can start enumerating the collection of names
before the whole collection is returned; when you use GetFiles, you
must wait for the whole array of names to be returned before you can
access the array. Therefore, when you are working with many files and
directories, EnumerateFiles can be more efficient.
You can check if file name has "UCU" in 4th position with string.IndexOf:
//string filename = "UCU";
if (file.FullName.IndexOf(filename) == 3)
I am moving files from source folder to destination folder. Before moving files, I am checking that directory exists or not which is working fine. The issue is with my second check where I want to make sure that folder is not empty before moving files but it is not giving me correct result.
public void MoveFilesFromTempToSourceTbl()
{
//Moving all files from temp folder to orig folder.
string sourceFolder = (twitterDO.Path + "\\" + msgDate.Year.ToString() + "\\" + msgDate.Month.ToString() + "\\" + msgDate.Day.ToString() + "_Temp").Replace("\\", #"\");
string destinationFolder = (twitterDO.Path + "\\" + msgDate.Year.ToString() + "\\" + msgDate.Month.ToString() + "\\" + msgDate.Day.ToString()).Replace("\\", #"\");
string pattern = "*.txt";
if (Directory.Exists(sourceFolder))
{
if (File.Exists(pattern))
{
foreach (var file in new DirectoryInfo(sourceFolder).GetFiles(pattern))
{
file.MoveTo(Path.Combine(destinationFolder, file.Name));
}
}
if (Directory.GetFiles(sourceFolder).Length == 0) //Before deleting make sure that Temp folder is empty.
Directory.Delete(sourceFolder, true); // Delete Temp folder after moving all the contents.
}
}
I know I am making some small mistake but not sure what it is. Following is the screenshot of the result which I got in immediate window.
http://imgur.com/FZvo9cj
There's a bit of redundancy in your current code. Starting with the if-checks, here's how I would approach this:
var sourceDirectory = new DirectoryInfo(sourceFolder); // remember this, it is reused
if (sourceDirectory.Exists)
{
// Look for the files in the directory, if none found, will be empty array
foreach (var file in sourceDirectory.GetFiles(pattern))
{
file.MoveTo(Path.Combine(destinationFolder, file.Name));
}
// Re-check the directory for any remaining files
if (sourceDirectory.GetFiles(pattern).Length == 0) //Before deleting make sure that Temp folder is empty.
sourceDirectory.Delete(); // Delete Temp folder after moving all the contents.
}
As a small performance improvement, you could replace sourceDirectory.GetFiles() with sourceDirectory.EnumerateFiles() in the for-loop. This will allow you to start moving them as the method finds them, not after they have all been found.
You are passing "*.txt" into the File.Exists() call when you need to be passing a path.
You can read the Documentation here
Alternatively you could use something like this:
Directory.GetFiles(destinationFolder).Contains(filename)
I agree with David here but also I think the flow of you logic should be adjusted a bit. The File.Exixts(filename); should occur inside the foreach.
That will allow you to iterate each file and if it exists do something.
Try adding the following to check if any files exist in the location:
bool exist = Directory.EnumerateFiles(sourceFolder, "*.txt").Any();