I have an strange problem I have an app that scan a directory and gets a list of files. it processes each file by reading it and doing some stuff. it works fine in the development computer but when I deploy it to the client it gives me the error. Here is the code
public void ProcessIMFiles()
{
DirectoryInfo di = new DirectoryInfo(Globals.ITMDIR);
FileInfo[] Files = di.GetFiles("*.txt");
foreach(FileInfo file in Files)
{
try
{
processThisIMFile(file.FullName);
movefile(file.FullName);
}
catch (Exception ex)
{
MessageBox.Show("error : " + ex.Message);
}
}
}
The error happens in the call to processThisIMFile(file.FullName) see below.
Globals.ITMDIR is a valid path.
private void processThisIMFile(string FileName)
{
string[] Fields = null;
setconnection();
DataTable dt = null;
try
{
string[] Lines = System.IO.File.ReadAllLines(FileName);
foreach (string line in Lines)
{
Fields = line.Split(Globals.delimiter);
if (Fields.Length == 7)
{
//stuff happens here
}
}//Try
catch (Exception e)
{
if (Interactive)
{
MessageBox.Show("Error in the Path: ->" + FileName);
writeToLog(true, "error opening file " + FileName);
}
}
}//end of processThisItemFile
the error happens in the "string[] Lines = System.IO.File.ReadAllLines(FileName)"
line. FileName comes from the di.GetFiles("*.txt"); when I show the actual path it looks ok to me. I have tried with UNC paths and with drive letters path as in C:\tmp\filename.txt or \\server\tmp\filename.txt both fail in the deplopyment machine with "The given path's is not supported" but it works fine in the development machine.
What is going on?
I'm wondering if this could be related to file.fullname somehow altering the file path string and giving an unacceptable result. Can you troubleshoot by using processThisIMFile(Path.GetFullPath(file))? Also, use messagebox.show(file.FullName) prior to processthisimfile to confirm that the result is as expected.
Related
I have the following trivial C# application that simply attempts to launch "jconsole.exe", which on my machine is located in C:\Programs\jdk16\bin.
using System;
using System.Diagnostics;
namespace dnet {
public class dnet {
static void Main( string[] args ) {
try {
Process.Start("jconsole.exe");
Console.WriteLine("Success!");
} catch (Exception e) {
Console.WriteLine("{0} Exception caught.", e);
}
}
}
}
If my PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin
it works perfectly. However, if the PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\\programs\jdk16\bin
(note the two backslashes between "c:" and "programs"), it fails with a win32 exception.
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at dnet.dnet.Main(String[] args)
Interestingly, in the same command prompt where I run the .NET program and get the exception, I can simply type "jconsole.exe", and the program will start. Windows appears to have no trouble finding the executable with the double backslash in the PATH, but Process.Start() does.
Why is the extra backslash in the PATH causing problems, and how I can get around the problem? I don't know where the executable I want to call will be located at runtime, so I'd rather rely on the PATH variable.
Not quite sure why the problem occurs. Though, I can think of one solution that works on my machine:
var enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
Console.WriteLine(enviromentPath);
var paths = enviromentPath.Split(';');
var exePath = paths.Select(x => Path.Combine(x, "mongo.exe"))
.Where(x => File.Exists(x))
.FirstOrDefault();
Console.WriteLine(exePath);
if (string.IsNullOrWhiteSpace(exePath) == false)
{
Process.Start(exePath);
}
I did find one para which gave me the idea for this solution. From the documentation for Process.Start
If you have a path variable declared in your system using quotes, you
must fully qualify that path when starting any process found in that
location. Otherwise, the system will not find the path. For example,
if c:\mypath is not in your path, and you add it using quotation
marks: path = %path%;"c:\mypath", you must fully qualify any process
in c:\mypath when starting it.
The way I read it, even though the PATH variable contained a valid path that Windows is able to use, Process.Start is unable to use it and needs the fully qualified path .
You can solve it if you first create a ProcessStartInfo.
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(#"\\", #"\");
Process.Start(psi);
You'll have to find out yourself how to manipulate the PATH to let it work for you. But this should solve any issues you might have with your PATH variable.
The accepted answer is incorrect.
cmd.exe will find applications with executable extensions first.
So when you have the files puma and puma.bat in C:\Ruby\bin\, then puma.bat will take precedence over puma.
If you start c:\ruby\bin\puma.bat from c:\redmine, it will start puma with current working directory c:\ruby\bin, and your web application will work.
However, if you start c:\ruby\bin\puma directly, it will start puma with the current working directory in c:\redmine and will subsequently fail.
So a corrected version looks more or less like this:
// FindAppInPathDirectories("ruby.exe");
public string FindAppInPathDirectories(string app)
{
string enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
string[] paths = enviromentPath.Split(';');
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
string[] executableExtensions = new string[] { ".exe", ".com", ".bat", ".sh", ".vbs", ".vbscript", ".vbe", ".js", ".rb", ".cmd", ".cpl", ".ws", ".wsf", ".msc", ".gadget" };
foreach (string extension in executableExtensions)
{
string fullFile = thisFile + extension;
try
{
if (System.IO.File.Exists(fullFile))
return fullFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + fullFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next extension
} // Next thisPath
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
try
{
if (System.IO.File.Exists(thisFile))
return thisFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + thisFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next thisPath
return app;
} // End Function FindAppInPathDirectories
I am currently writing a program in C# that will copy all user profile files to an external device (in this case, my home server).
When my code iterates through my files and folders, it throws an UnauthorizedAccessException.
I have Googled this and searched StackOverflow, but I am unable to find a clear solution that doesn't involve terminating my process. The idea is that it should copy the files and folders that have read permissions.
I had this when I first started, but I easily fixed it by limiting what directories I would backup (though I would prefer a full backup).
Here is my code:
FileInfo f = new FileInfo(_configuration.Destination);
if (!f.Directory.Exists)
{
f.Directory.Create();
}
string[] backupDirectories = new string[]
{
"Desktop",
"Documents",
"Downloads",
"Favorites",
"Links",
"Pictures",
"Saved Games",
"Searches",
"Videos",
".git",
".android",
".IdealC15",
".nuget",
".oracle_jre_usage",
".vs",
"Contacts"
};
foreach (string dirPath in backupDirectories)
{
DirectoryInfo dirInfo = new DirectoryInfo(_path + "\\" + dirPath);
if (dirInfo.Exists)
{
foreach (string dirP in Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories))
{
DirectoryInfo dirI = new DirectoryInfo(dirP);
if (dirI.Exists)
{
string dir = dirP.Replace(_path, _configuration.Destination);
try
{
Directory.CreateDirectory(dir);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create Directory: " + dir + Environment.NewLine);
});
} catch (Exception e)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create Directory: " + dir + Environment.NewLine);
});
continue;
}
foreach (FileInfo theFile in dirInfo.GetFiles("*", SearchOption.AllDirectories))
{
string newPath = theFile.FullName;
string file = newPath.Replace(_path, _configuration.Destination);
try
{
File.Copy(newPath, file, true);
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Create File: " + file + Environment.NewLine);
});
} catch (Exception ex)
{
textBox2.Invoke((MethodInvoker) delegate
{
textBox2.AppendText("Could NOT Create File: " + file + Environment.NewLine);
});
}
}
}
}
}
}
I apologise if the code is messy, but I will describe sort of what it is doing. The first bit checks if the backup folder exists on the external drive.
The second part says what folders I need to backup (if you're able to fix this and make it backup all directories with permissions, please help me in doing so).
The first loop starts the iteration for each of the backupDirectories. The second loop starts the iteration for each of the directories in the backup directory. The third loop starts the iteration for each of the folders in the backup directory.
The exception is thrown at Directory.GetDirectories(dirInfo.FullName, "*", SearchOption.AllDirectories), and it is trying to access C:\Users\MyName\Documents\My Music. Attempting to access it in explorer does give me a permissions error, though it isn't listed in explorer when I try going to "Documents" (I am in Windows 10 Pro).
As I recommended, since the Operating System authority is higher than the application, it is likely that you cannot do more than what the Operating System would allow you to do (that is to access or not to access certain folder).
Thus, folders' accessibility is best solved in the Operating System level.
But you could still do two things in the program level to minimize the damage when you search for the items.
To use Directory.AccessControl to know the access level of a directory before you do any query on it. This is not so easy, and there are elaborated answers about this here and also here.
To minimize the damage made by unauthorized access issues by using SearchOption.TopDirectoryOnly instead of SearchOption.AllDirectories, combined with recursive search for all the accessible directories. This is how you can code it
public static List<string> GetAllAccessibleDirectories(string path, string searchPattern) {
List<string> dirPathList = new List<string>();
try {
List<string> childDirPathList = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly).ToList(); //use TopDirectoryOnly
if (childDirPathList == null || childDirPathList.Count <= 0) //this directory has no child
return null;
foreach (string childDirPath in childDirPathList) { //foreach child directory, do recursive search
dirPathList.Add(childDirPath); //add the path
List<string> grandChildDirPath = GetAllAccessibleDirectories(childDirPath, searchPattern);
if (grandChildDirPath != null && grandChildDirPath.Count > 0) //this child directory has children and nothing has gone wrong
dirPathList.AddRange(grandChildDirPath.ToArray()); //add the grandchildren to the list
}
return dirPathList; //return the whole list found at this level
} catch {
return null; //something has gone wrong, return null
}
}
The function above minimize the damage caused by the unauthorized access only to the sub-directories which have the issue. All other accessible directories can be returned.
I have used NUnrar to extract my files :
NUnrar.Archive.RarArchive archive = NUnrar.Archive.RarArchive.Open(location + "1.rar");
foreach (RarArchiveEntry item in archive.Entries)
{
string path = Path.Combine(location, Path.GetFileName(item.FilePath));
item.WriteToFile(path);
}
If my file has no any sub directory all things works but if rar file has sub directory all of them extracted to same folder how i can keep model of sub directory and file places
I've had to do some experimenting to get NUnrar to work properly as well.
Perhaps the little success I had can help you.
RarArchive archive = RarArchive.Open(#"D:\Archives\Test.rar");
foreach (RarArchiveEntry entry in archive.Entries)
{
try
{
string fileName = Path.GetFileName(entry.FilePath);
string rootToFile = Path.GetFullPath(entry.FilePath).Replace(fileName, "");
if (!Directory.Exists(rootToFile))
{
Directory.CreateDirectory(rootToFile);
}
entry.WriteToFile(rootToFile + fileName, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
catch (Exception ex)
{
//handle your exception here..
}
}
The code I have already uses (Exception e) further up, so I had to use (Exception ex) instead.
It's probably sloppy code, and could do with a tidy up - but being as late as it is I'm inclined to leave it be as it 'works'..
NUnrar.Archive.RarArchive.WriteToDirectory("update.rar", Application.StartupPath,NUnrar.Common.ExtractOptions.ExtractFullPath | NUnrar.Common.ExtractOptions.Overwrite);
if "update.rar" is inside the same directory as the executable.
I'd think RarArchive.ExtractToDirectory(source, destination); should work.
Or using your loop, change it to string path = Path.Combine(location, item.FilePath);
While copying around 50 GB of data via local LAN share, due to connectivity issue copy failed at around 10 GB copied.
I have renamed copied 10GB of data directory to localRepository and then written a C# program to copy files from the remote server to destination, only if it is not found in local repository. If found move file from local repository to destination folder.
Although the code worked fine and accomplishes the task very well. I wonder, have I written the most efficient code? Can you find any improvements?
string destinationFolder = #"C:\DataFolder";
string remoteRepository = #"\\RemoteComputer\DataFolder";
string localRepository = #"\\LocalComputer\LocalRepository";
protected void Page_Load(object sender, EventArgs e)
{
foreach (string remoteSrcFile in Directory.EnumerateFiles(remoteRepository, "*.*", SearchOption.AllDirectories))
{
bool foundInLocalRepo = false; ;
foreach (var localSrcFile in Directory.EnumerateFiles(localRepository, "*.*", SearchOption.AllDirectories))
{
if (Path.GetFileName(remoteSrcFile).Equals(Path.GetFileName(localSrcFile)))
{
FileInfo localFile = new FileInfo(localSrcFile);
FileInfo remoteFile = new FileInfo(remoteSrcFile);
//copy this file from local repository
if (localFile.Length == remoteFile.Length)
{
try
{
File.Move(localSrcFile, PrepareDestinationPath(remoteSrcFile));
Debug.WriteLine(remoteSrcFile + " moved from local repo");
}
catch (Exception ex)
{
Debug.WriteLine(remoteSrcFile + " did not move");
}
foundInLocalRepo = true;
break;
}
}
}
if (!foundInLocalRepo)
{
//copy this file from remote repository
try
{
File.Copy(remoteSrcFile, PrepareDestinationPath(remoteSrcFile), false);
Debug.WriteLine(remoteSrcFile + " copied from remote repo");
}
catch (Exception ex)
{
Debug.WriteLine(remoteSrcFile + " did not copy");
}
}
}
}
private string PrepareDestinationPath(string remoteSrcFile)
{
string relativePath = remoteSrcFile.Split(new string[] { "DataFolder" }, StringSplitOptions.None)[1];
string copyPath = Path.GetFullPath(destinationFolder + relativePath);
Directory.CreateDirectory(Path.GetDirectoryName(copyPath));
return copyPath;
}
EDIT:
Based on answer given by Thomas I am attempting to zip the file.
Traditionally as an end user we use to zip a file and then copy. As a programmer can we zip and copy the file parallel? I mean the portion which has been zipped send it over the wire?
You are doing far too much work with the nested loop.
You should remove the inner "foreach" and replace it with some code that:
(1) Constructs the name of the file that you are looking for and
(2) Uses File.Exists() to see if exists, then
(3) Continues with the same block of code that you currently have following the "if (Path.GetFileName(remoteSrcFile)..." condition.
Something like this:
foreach (string remoteSrcFile in Directory.EnumerateFiles(remoteRepository, "*.*", SearchOption.AllDirectories))
{
string localSrcFile = Path.Combine(localRepository, Path.GetFileName(remoteSrcFile));
if (File.Exists(localSrcFile))
{
...
}
}
I would suggest zipping the files before moving. Try take a look at the very simple http://dotnetzip.codeplex.com/
Try zipping 1000 files a time, in that way, you don't have to run the for-loop that many times and establish new connections etc each time.
I have the following trivial C# application that simply attempts to launch "jconsole.exe", which on my machine is located in C:\Programs\jdk16\bin.
using System;
using System.Diagnostics;
namespace dnet {
public class dnet {
static void Main( string[] args ) {
try {
Process.Start("jconsole.exe");
Console.WriteLine("Success!");
} catch (Exception e) {
Console.WriteLine("{0} Exception caught.", e);
}
}
}
}
If my PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin
it works perfectly. However, if the PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\\programs\jdk16\bin
(note the two backslashes between "c:" and "programs"), it fails with a win32 exception.
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at dnet.dnet.Main(String[] args)
Interestingly, in the same command prompt where I run the .NET program and get the exception, I can simply type "jconsole.exe", and the program will start. Windows appears to have no trouble finding the executable with the double backslash in the PATH, but Process.Start() does.
Why is the extra backslash in the PATH causing problems, and how I can get around the problem? I don't know where the executable I want to call will be located at runtime, so I'd rather rely on the PATH variable.
Not quite sure why the problem occurs. Though, I can think of one solution that works on my machine:
var enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
Console.WriteLine(enviromentPath);
var paths = enviromentPath.Split(';');
var exePath = paths.Select(x => Path.Combine(x, "mongo.exe"))
.Where(x => File.Exists(x))
.FirstOrDefault();
Console.WriteLine(exePath);
if (string.IsNullOrWhiteSpace(exePath) == false)
{
Process.Start(exePath);
}
I did find one para which gave me the idea for this solution. From the documentation for Process.Start
If you have a path variable declared in your system using quotes, you
must fully qualify that path when starting any process found in that
location. Otherwise, the system will not find the path. For example,
if c:\mypath is not in your path, and you add it using quotation
marks: path = %path%;"c:\mypath", you must fully qualify any process
in c:\mypath when starting it.
The way I read it, even though the PATH variable contained a valid path that Windows is able to use, Process.Start is unable to use it and needs the fully qualified path .
You can solve it if you first create a ProcessStartInfo.
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(#"\\", #"\");
Process.Start(psi);
You'll have to find out yourself how to manipulate the PATH to let it work for you. But this should solve any issues you might have with your PATH variable.
The accepted answer is incorrect.
cmd.exe will find applications with executable extensions first.
So when you have the files puma and puma.bat in C:\Ruby\bin\, then puma.bat will take precedence over puma.
If you start c:\ruby\bin\puma.bat from c:\redmine, it will start puma with current working directory c:\ruby\bin, and your web application will work.
However, if you start c:\ruby\bin\puma directly, it will start puma with the current working directory in c:\redmine and will subsequently fail.
So a corrected version looks more or less like this:
// FindAppInPathDirectories("ruby.exe");
public string FindAppInPathDirectories(string app)
{
string enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
string[] paths = enviromentPath.Split(';');
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
string[] executableExtensions = new string[] { ".exe", ".com", ".bat", ".sh", ".vbs", ".vbscript", ".vbe", ".js", ".rb", ".cmd", ".cpl", ".ws", ".wsf", ".msc", ".gadget" };
foreach (string extension in executableExtensions)
{
string fullFile = thisFile + extension;
try
{
if (System.IO.File.Exists(fullFile))
return fullFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + fullFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next extension
} // Next thisPath
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
try
{
if (System.IO.File.Exists(thisFile))
return thisFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + thisFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next thisPath
return app;
} // End Function FindAppInPathDirectories