Background: I'm developing a WinForms application using C# with an OpenFileDialog & FileBrowserDialog that will 1) search for a specific string in the filenames of a specified source directory 2) copy files to consolidated directory 3) convert multiple files from excel to csv files, and then 3) convert all the generated csv files into 1 big csv file using a command line executable
Example: MSDN provides a code example that lists all of the directories and files that begin with the letter "c" in "c:\". at http://msdn.microsoft.com/en-us/library/ms143448.aspx so I based my code on that...
Problem: The code doesn't copy any files to the consolidated folder so I'm pretty sure the search doesn't work.
What should I change on here? It doesn't work :
string files = "*.xlsx";
void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, files))
{
// Is this the file we are looking for?
// check excel files for corp name in the filename.
if (f.Contains(m_sc.get_Corp()))
{
// check if thread is cancelled
if (m_EventStop.WaitOne(0, true))
{
// clean-up operations may be placed here
// ...
// inform main thread that this thread stopped
m_EventStopped.Set();
return;
}
else
{
string path = sDir;
string searchPattern = m_sc.get_Corp();
// A file has been found in this directory
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
try
{
// Copy each selected xlsx files into the specified TargetFolder
System.IO.File.Copy(FileName, consolidatedFolder + #"\" + System.IO.Path.GetFileName(FileName));
Log("File" + FileName + " has been copied to " + consolidatedFolder + #"\" + System.IO.Path.GetFileName(sourceFileOpenFileDialog.FileName));
// Convert each selected XLSX File to CSV Using the command prompt code...
}
}
}
}
The code you've posted does two separate search loops:
first:
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, files))
{
// Is this the file we are looking for?
// check excel files for corp name in the filename.
if (f.Contains(m_sc.get_Corp()))
{
then within that it also does:
string path = sDir;
string searchPattern = m_sc.get_Corp();
// A file has been found in this directory
DirectoryInfo di = new DirectoryInfo(path);
DirectoryInfo[] directories = di.GetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
foreach (FileInfo file in files)
{
In the first one you are looking for files matching m_sc.get_Corp();, in the second one you are lookinf for directories...
In fact... your code (pseudo-code?) makes no sense...
Try:
taking your time
tidying up the code yourself
if you rewrite it slowly and break this into smaller chunks, you might spot what you are doing wrong.
Try cleaning up a bit, below is some code that will put you on the path, I've excluded the CSV conversion and the merge, hopefully you will get the idea.
private void YourFileRoutine(string sourceDirectoryPath, string consolidatedDirectoryPath)
{
var excelFiles = new DirectoryInfo(sourceDirectoryPath).GetFiles().Where(x => x.Extension == ".xlsx");
//Copy all Excel Files to consolidated Directory
foreach (var excelFile in excelFiles)
{
FileInfo copiedFile = excelFile.CopyTo(String.Concat(consolidatedDirectoryPath, excelFile.Name)); // Make sure consolidatedDirectoryPath as a "\" maybe use Path.Combine()?
// ConvertToCSV( Do your CSV conversion here, the Path will be = Path.GetFullPath(copiedFile);
}
// Merge CSV's
var csvFiles = new DirectoryInfo(consolidatedDirectoryPath).GetFiles().Where(x => x.Extension == ".csv");
// SomeMergeMethod that iterates through this FileInfo collection?
}
Related
How to delete Files there names containing a specific string in a Directory and also all Subdirectories?
Given Filenames like:
EA myown EURJPY M15 3015494.mq5
EA myown EURJPY M15 3015494.ex5
EA self EURJPY M15 3098111 fine.mq5
EA self EURJPY M15 3098111 fine.ex5
Given Folderstructures like:
D:\TEMP\MYTEST
D:\TEMP\MYTEST\EURJPY
D:\TEMP\MYTEST\EURJPY\EURJPY_M15
Example: I want to delete ALL Files in all Subdirectories containing this String:
3015494
These Files are copied more than one time down of the Root-Folder "D:\TEMP\MYTEST" and also copied into the Subdirectories.
I try to write a little function for this. But i can delete Files into a given Folder, but not down into Subfolders ...
Last Code from me:
// call my function to delete files ...
string mypath = #"D:\TEMP\MYTEST\";
string myfilecontains = #"xx";
DeleteFile(mypath, true, myfilecontains);
// some code i found here and should delete just Files,
// but only works in Root-Dir.
// Also will not respect my need for Filename contains Text
public static bool DeleteFile(string folderPath, bool recursive, string FilenameContains)
{
//Safety check for directory existence.
if (!Directory.Exists(folderPath))
return false;
foreach (string file in Directory.GetFiles(folderPath))
{
File.Delete(file);
}
//Iterate to sub directory only if required.
if (recursive)
{
foreach (string dir in Directory.GetDirectories(folderPath))
{
//DeleteFile(dir, recursive);
MessageBox.Show(dir);
}
}
//Delete the parent directory before leaving
//Directory.Delete(folderPath);
return true;
}
What i have to change in this Code for my needs?
Or is there a complete different code something more helpfull?
I hope you have some good ideas for me to catch the trick.
DirectoryInfo dir = new DirectoryInfo(mypath);
// get all the files in the directory.
// SearchOptions.AllDirectories gets all the files in subdirectories as well
FileInfo[] files = dir.GetFiles("*.*", SearchOption.AllDirectories);
foreach (FileInfo file in files)
{
if (file.Name.Contains(myfilecontains))
{
File.Delete(file.FullName);
}
}
This is similar to hossein's answer but in his answer if the directory name contains the value of myfilecontains that file will get deleted as well which I would think you don't want.
//get the list of files in the root directory and all its subdirectories:
string mypath = #"D:\TEMP\MYTEST\";
string myfilecontains = #"xx";
var files = Directory.GetFiles(mypath, "*", SearchOption.AllDirectories).ToList<string>();
//get the list of file for remove
var forDelete = files.Where(x => x.Contains(myfilecontains));
//remove files
forDelete.ForEach(x => { File.Delete(x); });
hope this helps!
I have some folders and these folders have some text files and i need delete these files but i catch an error with my code!
var dateFolder = Directory.GetDirectories(#"data\stdate").Select(Path.GetDirectoryName).ToArray();
foreach (var dateFile in dateFolder)
{
var stDates =
Directory.GetFiles(#"data\stdate\" + dateFile + "date").Select(Path.GetFileName).ToArray();
foreach (var date in stDates)
{
File.Delete(#"data\stdate\" + dateFile + "date\\" + date);
}
Directory.Delete(#"data\stdate\" + dateFile + "date");
}
try this:
Directory.Delete("Path", true); //true: It will delete directory by given path, also folders and files in it.
System.IO.DirectoryInfo di = new DirectoryInfo(#"data\stdate");
//This for delete all file in "data\stdate"
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
//***************************For delete file in folder
//This for delete all Subfolder and his files in "data\stdate"
foreach (DirectoryInfo dir in di.GetDirectories())
{
dir.Delete(true);
}
//*************************
//This for delete the parent folder "stdate"
di.Delete();
i delete my original folder and i create it again!
if (!isDateEmpty)
{
Directory.Delete(#"data\stdate", true);
Directory.CreateDirectory(#"data\stdate");
}
I suggest that you use system environment variables, see here:
https://en.wikipedia.org/wiki/Environment_variable
The reason being, like you found out: sometimes the executable is not running in the directory you expected when you compiled the program.
EX:
String query = "%SystemDrive%";
str = Environment.ExpandEnvironmentVariables(query);
Delete(str, true);
That way it guarantees a predictable path as opposed to a relative one.
So basically i am making an app that will sync file types is different ways, I want to search the whole of a logical Drive for example C:\ for all text files.How ever once i find all the text files i want to apply an action for example move all text files to one location or email all text files to the users email.
I have found this code from a past Stack overflow post
public List<string> Search()
{
var files = new List<string>();
foreach (DriveInfo d in DriveInfo.GetDrives().Where(x => x.IsReady))
{
try
{
files.AddRange(Directory.GetFiles(d.RootDirectory.FullName, "*.txt", SearchOption.AllDirectories));
}
catch(Exception e)
{
Logger.Log(e.Message); // Log it and move on
}
}
return files;
}
But what i want to know is how do i do somthing when i find the files ?
The code you posted looks like it should fill List<string> files with strings representing names of files that have a .txt extension.
It should be as simple as iterating over the value returned from the function and doing as you please with them.
This code should (untested) check for a target directory, create it if it doesn't exist, and then copy each file returned from Search() to the target path.
List<string> results = Search();
String targetPath = "C:/TargetDirectory/";
if (!System.IO.Directory.Exists(targetPath))
System.IO.Directory.CreateDirectory(targetPath);
foreach (string aFileStr in results)
{
String sourceFile = aFileStr;
String destFile = Path.Combine(targetPath, Path.GetFileName(aFileStr));
System.IO.File.Copy(sourceFile, destFile, true);
}
You would do a foreach on the list of strings that that function returns.
I'm not quite sure if I understand you correctly. If you just want to know how to process your filelist, you could for instance do the following:
var filelist = Search();
foreach (var s in filelist) {
string fn = System.IO.Path.GetFileName(s);
string dest = System.IO.Path.Combine("c:\\tmp", fn);
System.IO.File.Copy(s, dest, true);
}
which will copy all files in filelist to c:\tmp and overwrite files with equal filename.
I'm trying this function, which copies all files from a folder, and relative subfolders with files to another location:
using System.IO;
private static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting)
{
bool ret = true;
try
{
SourcePath = SourcePath.EndsWith(#"\") ? SourcePath : SourcePath + #"\";
DestinationPath = DestinationPath.EndsWith(#"\") ? DestinationPath : DestinationPath + #"\";
if (Directory.Exists(SourcePath))
{
if (Directory.Exists(DestinationPath) == false)
Directory.CreateDirectory(DestinationPath);
foreach (string fls in Directory.GetFiles(SourcePath))
{
FileInfo flinfo = new FileInfo(fls);
flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
}
foreach (string drs in Directory.GetDirectories(SourcePath))
{
DirectoryInfo drinfo = new DirectoryInfo(drs);
if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false || drs.Substring(drs.Length-8) == "archive")
ret = false;
}
}
else
{
ret = false;
}
}
catch (Exception e)
{
Console.WriteLine("{0} {1} {2}", e.Message, Environment.NewLine + Environment.NewLine, e.StackTrace);
ret = false;
}
return ret;
}
It works good until you have to copy the folder into another location, but when you have to create a folder in itself (In my example I'm doing a subfolder called "archive" to keep track of the last folder files changes) it goes in infinite loops, because it keeps rescanning itself in the Directory.GetDirectories foreach loop, finding the newly created subfolders and going on nesting the same subfolder over and over until it reaches a "Path name too long max 260 charachters limit exception".
I tried to avoid it by using the condition
|| drs.Substring(drs.Length-8) == "archive")
which should check the directory name, but it doesn't seem to work.
I thought than, different solutions like putting a max subfolders depth scan (I.E max 2 subfolders) so it doesn't keep rescanning all the nested folders, but I can't find such property in Directory object.
I cannot copy the whole thing to a temp folder and then into the real folder because the next time I will scan it, it will rescan archive folder too.
I tought about putting all the directory listing in an ArrayList of Directory objects or so so maybe I can check something like DirName or so but I don't know if such property exists.
Any solution?
This is a case where recursion doesn't really work, as the list of directories and files always changes as you copy. A better solution is to get the list of all files and folders in advance.
You can get all files and directories in a tree using the Directory.GetFiles(String,String,SearchOption) and Directory.GetDirectories(String,String,SearchOption) with SearchOption set to SearchOption.AllDirectories. These will return all files and all directories respectively.
You can follow these steps to copy the files:
Get the list of all source directories and sort them in ascending order. This will ensure that parent directories appear before their child directories.
Create the target directory structure by creating the child directories in their sorted order. You won't get any path conflicts as the sort order ensures you always create the parent folders before the child folders
Copy all the source files to the target directories as before. Order doesn't really matter at this point as the target directory structure already exists.
A quick example:
static void Main(string[] args)
{
var sourcePath = #"c:\MyRoot\TestFolder\";
var targetPath = #"c:\MyRoot\TestFolder\Archive\";
var directories=Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories);
var files = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories);
if(!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
foreach (var directory in directories)
{
var relativePath = GetRelativePath(sourcePath, directory);
var toPath = Path.Combine(targetPath, relativePath);
if (!Directory.Exists(toPath))
{
Directory.CreateDirectory(toPath);
}
}
foreach (var file in files)
{
var relativePath = GetRelativePath(sourcePath, file);
var toPath = Path.Combine(targetPath, relativePath);
if (!File.Exists(toPath))
File.Copy(file,toPath);
}
}
//This is a very quick and dirty way to get the relative path, only for demo purposes etc
private static string GetRelativePath(string rootPath, string fullPath)
{
return Path.GetFullPath(fullPath).Substring(rootPath.Length);
}
I wanna do a C# application that does this:
Selects a folder
Copies all the files from that folder into that folder +/results/
Very simple, but can't get it work.
Here is my code:
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
foreach (string file in files)
{
MessageBox.Show(Path.GetFullPath(file));
//string path=Path.Combine(Path.GetFullPath(file), "results");
//MessageBox.Show(path);
string path2 = Path.GetDirectoryName(file);
path2 = Path.Combine(Path.GetDirectoryName(file), #"results\");
path2 = Path.Combine(path2, file);
MessageBox.Show(path2);
}
First, create the destination directory, if not exists
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
string destPath = Path.Combine(folderBrowserDialog1.SelectedPath, "results");
if(Directory.Exists(destPath) == false)
Directory.CreateDirectory(destPath);
then inside your loop
foreach (string file in files)
{
string path2 = Path.Combine(destPath, Path.GetFileName(file));
File.Move(file, path2);
}
Please note that File.Move cannot be used to overwrite an existing file.
You will get an IOException if the file exist in the destination directory.
If you only want to copy, instead of Move, simply change the File.Move statement with File.Copy(file, path2, true);. This overload will overwrite your files in the destination directory without questions.
If you are trying to move the files (and not copy them) to the new sub-folder then...
DirectoryInfo d = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
foreach (FileInfo f in d.GetFiles())
{
string fold = Path.Combine(f.DirectoryName, #"results\");
if (!Directory.Exists(fold))
Directory.CreateDirectory(fold);
File.Move(f.FullName, Path.Combine(fold, f.Name));
}
This is just an example to answer the question directly but you should also handle exceptions, etc. For instance, this example assumes the user will have permission to create the directory. Furthermore, it assumes file(s) do not already exist in the destination directory with the same name(s). How you handle such scenarios depends on your requirements.
If you want to relocate the entire directory, you can use Directory.Move to achieve this.
string path1 = Path.GetDirectoryName(file);
string path2 = Path.Combine(Path.GetDirectoryName(file), #"results\");
Directory.Move(path1, path2);
Or if you just want to copy the folder (without deleting the first directory), you'll need to do it manually.
string path1 = Path.GetDirectoryName(file);
string path2 = Path.Combine(Path.GetDirectoryName(file), #"results\");
foreach(var file in Directory.GetFiles(path1))
{
File.Copy(file, Path.Combine(path2, file));
// File.Move(file, Path.Combine(path2, file)); // use this to move instead of copy
}
I haven't tested this, so some modifications might be necessary