I have the bit of code that searches the entire computer for a file and once found, should return that file. The problem is in the second function, the recursive one. Once the file is found, it should return, which it does, but for some reason, even after returning the value, it continues the recursive search.
I don't get it. I'd still consider myself new to programming so please explain in detail if you see what I'm doing wrong.
public string SearchDirectory(string dir, string fileName)
{
string foundDir = "";
bool fileFound = false;
// Gets all files from directory and creates list of matches to fileName
try
{
foreach (string match in Directory.GetFiles(dir, fileName))
{
// Returns the first found match as a path and breaks loop
Console.WriteLine("Checked path: " + dir + ".");
if (File.Exists(dir + #"\" + fileName))
{
Console.WriteLine("FOUND!!");
fileFound = true;
foundDir = dir;
break;
}
if (fileFound == true)
{
break;
}
}
}
catch
{
Console.WriteLine("Access to path: " + dir + " denied.");
}
// If fileName isn't found in directory, it searches each new directory
// The last directory it will check is the last one in the original directory
if (fileFound == false)
{
try
{
foreach (string newDirectory in Directory.GetDirectories(dir))
{
Console.WriteLine("Checked path: " + dir + ".");
SearchDirectory(newDirectory, fileName);
}
}
catch
{
Console.WriteLine("Access to path: " + dir + " denied.");
}
// fileName does not exist in starting directory
}
else
{
return foundDir;
}
return "";
}
Your recursive call is ignoring the returned value. You should instead check to see if it found something so you can stop searching more sub-directories.
foreach (string newDirectory in Directory.GetDirectories(dir))
{
Console.WriteLine("Checked path: " + dir + ".");
var result = SearchDirectory(newDirectory, fileName);
if(result != "") return result;
}
You could just do this instead:
public string SearchDirectory(string dir, string fileName)
{
return Directory
.EnumerateFiles(dir, fileName, SearchOption.AllDirectories)
.FirstOrDefault() ?? "";
}
Related
I have the following code:
static void Scan(string path)
{
try{
foreach (var file in Directory.EnumerateFiles(path, "zfsdfsdfsb.txt")){
Console.WriteLine("FILE: " + file);
}
foreach (var dir in Directory.EnumerateDirectories(path)){
Console.WriteLine("DIRECTORY: " + dir);
Scan(dir);
}
}
}
And i want to stop the function and acess the variable as soon as
Console.WriteLine("FILE: " + file);
has been triggered.
I tried to return it, but it diddnt do anything, how can i set a variable and stop the function as soon as the file has been found?
Change your void to string
static string Scan(string path).
Then, inside your loop, return the string when found:
foreach (var file in Directory.EnumerateFiles(path, "zfsdfsdfsb.txt")){
Console.WriteLine("FILE: " + file);
return file;
}
You'll also need to return a string at the end of the method if nothing was found.
if you are recursively looking for a file that matches a given pattern
static string Scan(string path)
{
try{
foreach (var file in Directory.EnumerateFiles(path, "zfsdfsdfsb.txt")){
Console.WriteLine("FILE: " + file);
return file;
}
foreach (var dir in Directory.EnumerateDirectories(path)){
Console.WriteLine("DIRECTORY: " + dir);
var ret = Scan(dir);
if(ret != null)
return ret;
}
}
return null;
}
if you are looking for a specific file replace first loop with
var fpath = Path.Combine(path,"zfsdfsdfsb.txt");
if (File.Exists(fpath))
return fpath;
THIS QUESTION IS ANSWERED!
I need to get all files from dropbox. But I cant finish my recursive function, it doesnt work, i have an idea why it doesnt work, but i dont know how to fix it
private void getAllFiles(string path)
{
var dropCon = DatabaseDropbox.Instance();
if (dropCon.IsConnect())
{
ICloudDirectoryEntry folder = dropCon.DropboxStorage.GetFolder(path);
foreach (ICloudFileSystemEntry fsentry in folder)
{
if (fsentry is ICloudDirectoryEntry) // IF FOLDER
{
}
else // IF FILE
{
Console.WriteLine(path + " " + fsentry.Name);
ListViewItem lvi = new ListViewItem(fsentry.Name);
lvi.SubItems.Add(path);
listViewFolders.Items.Add(lvi);
}
}
foreach (ICloudFileSystemEntry fsentry in folder)
{
if (fsentry is ICloudDirectoryEntry) // IF FOLDER
{
var mpath = path + "/" + fsentry.Name;
getAllFiles(mpath);
}
else // IF FILE
{
Console.WriteLine(path + " " + fsentry.Name);
ListViewItem lvi = new ListViewItem(fsentry.Name);
lvi.SubItems.Add(path);
listViewFolders.Items.Add(lvi);
}
}
}
}
If its finds file, it adds it to the list (C# form).
HOW IT DOESNT WORK:
It will list all files in the first directory,
then it will go to the first folder found, lets call that folder "fol1".
After it scans all "fol1", it adds found files to the list, which is good.
But then , when it should go back and search for more files in other directories , "fol2","fol3". Recursion just exists itself and it doesnt do that. So thats my problem.
FOUND RESULTS:
https://gyazo.com/fda8fde13dfbf32f35d39b87712b5751
ACTUAL FOLDERS:
https://gyazo.com/619e5c46bbc113d7d23a56b225f4f209
https://gyazo.com/265034521f317bf0d308910929d1664c
https://gyazo.com/ed9fe5375e1b21f54bbd1f127085c255
Thanks.
WORKING CODE :
private void getAllFiles(string path)
{
var dropCon = DatabaseDropbox.Instance();
if (dropCon.IsConnect())
{
ICloudDirectoryEntry folder = dropCon.DropboxStorage.GetFolder(path);
foreach (ICloudFileSystemEntry fsentry in folder)
{
if (fsentry is ICloudDirectoryEntry) // IF FOLDER
{
var mpath = path + "/" + fsentry.Name;
getAllFiles(mpath);
}
else // IF FILE
{
Console.WriteLine(path + " " + fsentry.Name);
ListViewItem lvi = new ListViewItem(fsentry.Name);
lvi.SubItems.Add(path);
listViewFolders.Items.Add(lvi);
}
}
}
}
private void getAllFiles(string path)
{
var dropCon = DatabaseDropbox.Instance();
if (dropCon.IsConnect())
{
ICloudDirectoryEntry folder = dropCon.DropboxStorage.GetFolder(path);
foreach (ICloudFileSystemEntry fsentry in folder)
{
if (fsentry is ICloudDirectoryEntry) // IF FOLDER
{
var mpath = path + "/" + fsentry.Name;
getAllFiles(mpath);
}
else // IF FILE
{
Console.WriteLine(path + " " + fsentry.Name);
ListViewItem lvi = new ListViewItem(fsentry.Name);
lvi.SubItems.Add(path);
listViewFolders.Items.Add(lvi);
}
}
}
}
I have a situation where the user will enter the name of the file and at run-time (without specifying the path). And i must find out the file by c# code.
I have seen a function GetFullPath() but it just give the current directory path appended by fileName entered by user at run-time.
string fullPath;
Console.WriteLine("please enter teh name of the file to be searched");
String fileName = Console.ReadLine();
fullPath = Path.GetFullPath(fileName);
Is there any such way exist in c# to get full path of a file specified at run time ? (Without specifying about the path). I can convince the user for specifying the Drive (C:/D:/E:...) but for writing the full path at run time to find that file they will not agree.
EDIT: My try is this: (but it gives access denied) please help me if i am not smart enough to go to each directory and do not try to open the secured folder until i get my file.
public static string Search(string fileName)
{
string fullPath = string.Empty;
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal currentPrincipal = new WindowsPrincipal(currentIdentity);
if (currentPrincipal.IsInRole(WindowsBuiltInRole.Administrator))
{
try
{
foreach (string fpath in Directory.GetFiles("F:\\", "*", SearchOption.AllDirectories))
{
try
{
if (fpath.Substring(fpath.LastIndexOf("\\") + 1).ToUpper().Contains(fileName.ToUpper()))
fullPath = fpath;
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Access denied to folder1: " + fullPath);
}
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Access denied to folder2: " + fullPath);
}
}
else
{
Console.WriteLine("You are not authorized");
}
return fullPath;
}
If you're searching for a file you can use the following to search all directories. Assuming the user inputs the entire filename (including the extension) and a source drive/location.
string fullPath = string.Empty;
Console.WriteLine("please enter the name of the file to be searched");
String fileName = Console.ReadLine();
foreach(string fpath in Directory.GetFiles("C:\\", "*", SearchOption.AllDirectories))
{
if (fpath.Substring(fpath.LastIndexOf("\\") + 1).ToUpper() == fileName.ToUpper())
fullpath = fpath;
}
Alternatively, if the user inputs part of the file (excluding extention) use..
foreach(string fpath in Directory.GetFiles("C:\\", "*", SearchOption.AllDirectories))
{
if (fpath.Substring(fpath.LastIndexOf("\\") + 1).ToUpper().Contains(fileName.ToUpper()))
fullpath = fpath;
}
Add to an array or list incase multiple results (paths) are found.
Like so..
var foundPaths = Directory.GetFiles("C:\\", "*", SearchOption.AllDirectories)
.Where(x => x.ToUpper().Contains(fileName.ToUpper()))
.Select(x => x)
.ToList();
I found solution my self, I am doing recursive call until i don't get file to be searched:
List<string> directories = new List<string>(Directory.GetDirectories(driveName));
string name=null;
foreach(string directry in directories)
{
if (GetFileInformation(directry, out name))
{
try
{
DirSearch(directry, fileName, ref foundVar);
}
catch (System.Exception excpt)
{
Console.WriteLine("from except msg :" + excpt.Message);
if(foundVar==true)
{
break;
}
}
}
}
And then the function definition is :
public static void DirSearch(string sDir, string fileName, ref bool foundVar)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d, fileName))
{
if (Path.GetFileName(f) == fileName)
{
Console.WriteLine("directory is and inside it is " + f);
OpenExeFile(f);
foundVar = true;
break;
}
}
DirSearch(d, fileName, ref foundVar);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
I wrote an app for going through very large fileshares and while it copies them to the new location, another HD in this case, it breaks what's being copied over into folders containing 4,500 or less items(Libraries to be synced to sharepoint online). Compensating for long file paths. Here is a code sample of the functions I have working in tandem that takes in the source and destination then does the copying breaking described above:
Edit:
Alright I found a solution and this method below is working as I want it to, it is really slow as you can imagine looking at how I have it counting the childitems as it's running though so if anyone has a better/faster solution to the problem please feel free to post it. Otherwise, thank you all very much for the help, it's much appreciated. Here's the code I currently have:
#region Recursive_Copy
public static List<string> OutOfReachAreas = new List<string>();
private static List<FileInfo> Overflow = new List<FileInfo>();
private static List<string> AccessDeniedList = new List<string>();
private static bool FirstTime = true;
private static int LibraryCount { get; set; }
private static bool ToSwith = false;
private static int CountLimit = 4250;
public static void RecursiveCopy(string SourceDir, string DestDir)
{
if (!FirstTime)
{
LibraryCount =
((Directory.GetDirectories((Program.DestinationContainer + "\\" + "Library" + Program.LibraryCounter.ToString()), "*", SearchOption.AllDirectories).Count())
+ (Directory.GetFiles((Program.DestinationContainer + "\\" + "Library" + Program.LibraryCounter.ToString()), "*", SearchOption.AllDirectories).Count()));
}
if (LibraryCount <= CountLimit && !FirstTime)
{
try
{
DirectoryInfo dir = new DirectoryInfo(SourceDir);
DirectoryInfo[] dirs = dir.GetDirectories();
FileInfo[] files = dir.GetFiles();
string CurrentLibrary = "Library" + Program.LibraryCounter.ToString();
if (!Directory.Exists(DestDir))
{
Directory.CreateDirectory(DestDir);
}
if (Overflow.Count() != 0)
{
foreach (var OverflowInst in Overflow)
{
string NewestLibrary = Program.DestinationContainer + "\\" + "Library" + Program.LibraryCounter + "\\" + OverflowInst.Name;
if (!File.Exists(NewestLibrary))
{
OverflowInst.CopyTo(NewestLibrary, false);
}
}
Overflow.Clear();
}
foreach (var file in files)
{
try
{
DirectoryInfo TestPath = new DirectoryInfo(Program.DestinationContainer + "\\" + CurrentLibrary);
int TestPathCount = (TestPath.GetDirectories("*", SearchOption.AllDirectories).Count()) + (TestPath.GetFiles("*", SearchOption.AllDirectories).Count());
if (TestPathCount <= CountLimit)
{
string temppath = Path.Combine(DestDir, file.Name);
DirectoryInfo TestTemp = new DirectoryInfo(temppath);
if (!TestTemp.Exists && !AccessDeniedList.Contains(file.Name))
{
file.CopyTo(temppath, true);
}
}
else
{
FileInfo OverflowToAdd = new FileInfo(file.FullName);
Overflow.Add(OverflowToAdd);
}
}
catch (UnauthorizedAccessException)
{
AccessDeniedList.Add(file.Name);
}
}
foreach (var subDir in dirs)
{
DirectoryInfo TestPath = new DirectoryInfo(Program.DestinationContainer + "\\" + CurrentLibrary);
int TestPathCount = (TestPath.GetDirectories("*", SearchOption.AllDirectories).Count()) + (TestPath.GetFiles("*", SearchOption.AllDirectories).Count());
if (TestPathCount <= CountLimit)
{
if (ToSwith)
{
ToSwith = false;
string PathToSwitch = Program.DestinationContainer + "\\" + "Library" + Program.LibraryCounter.ToString();
RecursiveCopy(SourceDir, PathToSwitch);
}
string temppath = Path.Combine(DestDir, subDir.Name);
RecursiveCopy(subDir.FullName, temppath);
}
else
{
DirectoryInfo CurrentDir = new DirectoryInfo(DestDir);
RecursiveCopy(SourceDir, (Program.DestinationContainer + "\\" + "Library" + Program.LibraryCounter.ToString()));
}
}
}
catch (PathTooLongException)
{
DirectoryInfo DirInst = new DirectoryInfo(SourceDir);
OutOfReachAreas.Add(DirInst.FullName);
}
catch (Exception e)
{
Console.WriteLine("\nError During Copying:\n" + e.Message);
}
}
else
{
++Program.LibraryCounter;
FirstTime = false;
ToSwith = true;
string LibraryToMake = Program.DestinationContainer + "\\" + "Library" + (Program.LibraryCounter.ToString());
Console.WriteLine("Building Library" + (Program.LibraryCounter.ToString()) + "...");
Directory.CreateDirectory(LibraryToMake);
RecursiveCopy(SourceDir, LibraryToMake);
}
}
#endregion
Like chais said in comments, you need the subdirectory search to be recursive.
The MS example calls itself for EACH subdirectory, so it walks the entire directory tree. You could do something similar by replacing:
foreach (var dir in FolderList1)
{
Destination = Destination + "\\" + dir.Name;
CopyItems(dir, Destination);
}
with
foreach (var dir in FolderList1)
{
Destination = Destination + "\\" + dir.Name;
CopyItems(dir, Destination);
foreach (Directory subDir in dir.GetDirectories())
{
BreakMain(subDir, Destination);
}
}
You've got some other things that will have to be fixed to move to this recursive design, but that's the jist of the MS example.
I have a windows service , that takes files with metadata(FIDEF) and corresponding video file and , translates the XML(FIDEF) using XSLT .
I get the file directory listing for FIDEF's and if a video file of the same name exists it translates it. That works ok , but it is on a timer to search every minute. I am trying to handle situations where the same file name enters the input directory but is already in the output directory. I just have it changing the output name to (copy) thus if another file enters i should get (copy)(copy).mov but the service won't start with filenames of the same directory already in the output , it works once and then does not seem to pick up any new files.
Any Help would be great as I have tried a few things with no good results. I believe its the renaming methods, but I've put most of the code up in case its a clean up issue or something else.
(forgive some of the names just trying different things).
private void getFileList()
{
//Get FILE LIST FROM Directory
try
{
// Process Each String/File In Directory
string result;
//string filename;
filepaths = null;
filepaths = Directory.GetFiles(path, Filetype);
foreach (string s in filepaths)
{
for (int i = 0; i < filepaths.Length; i++)
{
//Result Returns Video Name
result = Path.GetFileNameWithoutExtension(filepaths[i]);
FileInfo f = new FileInfo(filepaths[i]);
PreformTranslation(f, outputPath + result , result);
}
}
}
catch (Exception e)
{
EventLog.WriteEntry("Error " + e);
}
}
private void MoveVideoFiles(String Input, String Output)
{
File.Move(Input, Output);
}
private string GetUniqueName(string name)
{
//Original Filename
String ValidName = name;
//remove FIDEF from filename
String Justname1 = Path.GetFileNameWithoutExtension(name);
//get .mov extension
String Extension2 = Path.GetExtension(Justname1);
//get filename with NO extensions
String Justname = Path.GetFileNameWithoutExtension(Justname1);
//get .Fidef
String Extension = Path.GetExtension(name);
int cnt = 0;
//string[] FileName = Justname.Split('(');
//string Name = FileName[0];
while (File.Exists(ValidName)==true)
{
ValidName = outputPath + Justname + "(Copy)" + Extension2 + Extension;
cnt++;
}
return ValidName;
}
private string getMovFile(string name)
{
String ValidName = name;
String Ext = Path.GetExtension(name);
String JustName = Path.GetFileNameWithoutExtension(name);
while(File.Exists(ValidName))
{
ValidName = outputPath + JustName + "(Copy)" + Ext;
}
return ValidName;
}
//Preforms the translation requires XSL & FIDEF name.
private void PreformTranslation(FileInfo FileName, String OutputFileName , String result)
{
string FidefName = OutputFileName + ".FIDEF";
String CopyName;
String copyVidName = outputPath + result;
XslCompiledTransform myXslTransform;
myXslTransform = new XslCompiledTransform();
try
{
myXslTransform.Load(XSLname);
}
catch
{
EventLog.WriteEntry("Error in loading XSL");
}
try
{ //only process FIDEF's with corresponding Video file
if (AllFidef == "no")
{
//Check if video exists if yes,
if (File.Exists(path + result))
{
//Check for FIDEF File Already Existing in the Output Directory.
if (File.Exists(FidefName))
{
//Get unique name
CopyName = GetUniqueName(FidefName);
copyVidName= getMovFile(copyVidName);
//Translate and create new FIDEF.
//double checking the file is here
if (File.Exists(outputPath + result))
{
myXslTransform.Transform(FileName.ToString(), CopyName);
File.Delete(FileName.ToString());
MoveVideoFiles(path + result, copyVidName);
}
////Move Video file with Corresponding Name.
}
else
{ //If no duplicate file exsists in Directory just move.
myXslTransform.Transform(FileName.ToString(), OutputFileName + ".FIDEF");
MoveVideoFiles(path + result, outputPath + result);
}
}
}
else
{
//Must have FIDEF extension
//Processes All FIDEFS and moves any video files if found.
myXslTransform.Transform(FileName.ToString(), OutputFileName + ".FIDEF");
if (File.Exists(path + result))
{
MoveVideoFiles(path + result, outputPath + result);
}
}
}
catch (Exception e)
{
EventLog.WriteEntry("Error Transforming " + "FILENAME = " + FileName.ToString()
+ " OUTPUT_FILENAME = " + OutputFileName + "\r\n" +"\r\n"+ e);
}
}
There is a lot wrong with your code. getFileList has the unneeded inner for loop for starters. Get rid of it. Your foreach loop has s, which can replace filepaths[i] from your for loop. Also, don't do outputPath + result to make file paths. Use Path.Combine(outputPath, result) instead, since Path.Combine handles directory characters for you. Also, you need to come up with a better name for getFileList, since that is not what the method does at all. Do not make your method names liars.
I would simply get rid of MoveVideoFiles. The compiler just might too.
GetUniqueName only works if your file name is of the form name.mov.fidef, which I'm assuming it is. You really need better variable names though, otherwise it will be a maintenance nightware later on. I would get rid of the == true in the while loop condition, but that is optional. The assignment inside the while is why your files get overwritten. You always generate the same name (something(Copy).mov.fidef), and as far as I can see, if the file exists, I think you blow the stack looping forever. You need to fix that loop to generate a new name (and don't forget Path.Combine). Maybe something like this (note this is untested):
int copyCount = 0;
while (File.Exists(ValidName))
{
const string CopyName = "(Copy)";
string copyString = copyCount == 0 ? CopyName : (CopyName + "(" + copyCount + ")");
string tempName = Justname + copyString + Extension2 + Extension;
ValidName = Path.Combine(outputPath, tempName);
copyCount++;
}
This generates something(Copy).mov.fidef for the first copy, something(Copy)(2).mov.fidef for the second, and so on. Maybe not what you want, but you can make adjustments.
At this point you have a lot to do. getMovFile looks as though it could use work in the same manner as GetUniqueName. You'll figure it out. Good luck.