Using Process.Start in C# - c#

I want to start python aplication from C# so I use method Process. After I ran it and click the button I get
System.ComponentModel.Win32Exception: The system cannot find the file
specified
In either case. What's wrong?
int counter = 0;
private void button1_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
counter++;
TextBox1.Text = counter.ToString();
//Process.Start("Python.exe", "C:\\Users\\kamil\\source\\PythonApplication2\\PythonApplication2.py");
Process.Start("IExplore.exe", "www.northwindtraders.com");
}

The issue can be the full path of python.exe and I explore.exe. You can specify full path for them. Even a path can be added to PATH env variable. If a path is specified in PATH environment vatriable you don't need to specify the full path. You can change it like this:
var old = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine)
var new = old + #"Full path, here you don't need to escape double quotes."
Environment.SetEnvironmentVariable("PATH", new, EnvironmentVariableTarget.Machine)
It is a good practice to include path inside #"" here special characters don't need escaping.

Related

How can I pass a file/file path from one Button_Click event to another in C#?

I have a fileupload control (FileUpload1) in my webform which I use to load an excel file. I use a button called btn_open to display it in a gridview on click.
I also save the file using FileUpload1.SaveAs() method in a server folder.
Now I have another button called btn_edit which on click needs to use the same
file that I just loaded to do another set of operations.
How do I pass this file/file path from btn_open_Click to btn_edit_Click? I do not want to specify the exact location on the code. There will be multiple times I will open new excel files so I don't want to specify the file path to the server for every new file.This needs to happen programatically. Also, I want to avoid using Interop if its possible.
The following code snippet might make things more clear as to what I want to do.
protected void btn_open_Click(object sender, EventArgs e)
{
string fileExtension = System.IO.Path.GetExtension(FileUpload1.FileName);
if (fileExtension.ToLower() == ".xlsx" || fileExtension.ToLower() == ".xls")
{
string path = Path.GetFileName(FileUpload1.FileName); //capture the file name of the file I have uploaded
path = path.Replace(" ", ""); // if there is any spacing between the file name it will remove it
FileUpload1.SaveAs(Server.MapPath("~/ExcelFile/") + path); //saves to Server folder called ExcelFile
String ExcelPath = Server.MapPath("~/ExcelFile/") + path; // Returns the physical file path that corresponds to the specified virtual path.
.
.
*code to display it in gridview*
.
.
}
else
{
Console.Writeline("File type not permissible");
}
}
protected void btn_edit_Click(object sender, EventArgs e)
{
//HOW DO I PASS THE ABOVE FILE HERE PROGRAMATICALLY WITHOUT SPECIFYING IT'S EXACT LOCATION ON THE SERVER??
}
Using Session variable helped me solve my problem. Hopefully it will be helpful to other people who might encounter similar issue.
On the first button (in my case btn_open_Click), add:
Session["myXlsPath"] = ExcelFilePath;
Note: "myXlsPath" is just a name I created for my Session variable. ExcelFilePath is the path of my excel file that I want to pass to the other button.
On the button you want to pass the file path to (in my case btn_edit_Click), add:
string ExcelFilePath = (string)Session["myXlsPath"];

Copy entire directory with button from two dynamic locations

Okay, I have a button (button1) which I want to copy the static directory to the chosen directory. Essentially I have textbox1 in which different numeric values are added which correlate with different directories. I have a dictionary that sets the string to mapping which links to codes from textbox2 to the path of the origination folder. . This determines where we copy our data from. I want this data to then be copied into the folder selected in textbox2 through the folderBrowserDialog1.ShowDialog(); command. how to i create the dictionary and where do i put it for textbox1, and how do i then get the button to take whatever is in textbox1 and copy the entire directory to textbox2?
private Dictionary<string, string> mapping = new Dictionary<string, string>
{
{ "111", #"C:\Program Files\Example" },
{ "112", #"C:\Program Files\Example2" },
{ "113", #"C:\Program Files\Example3" },
};
public static string[] GetFiles(string mapping);
public static void Copy(string sourceFileName, string destFileName);
private void button2_Click(object sender, EventArgs e)
{
string destination = textBox1.Text;
foreach (var f in Directory.GetFiles(mapping))
{
File.Copy(Path.Combine(mapping, f)); destination;
}
}
Here is an answeer to "How copy an entire directory of files":
Use Directory.GetFiles() (see documentation) to get a list of all files in a directory.
Then use File.Copy() (see documenation) to copy a single file:
foreach(var f in Directory.GetFiles(srcPath))
{
File.Copy(Path.Combine(srcPath, f), dstPath);
}
EDIT
Directory.GetFiles() requires a path:
private void button2_Click(object sender, EventArgs e)
{
string destination = textBox1.Text;
string srcdir = mapping["111"];
foreach(var f in Directory.GetFiles(srcdir))
{
string srcpath = Path.Combine(srcdir, f)
File.Copy(srcpath, destination);
}
}
I'm not 100% sure I understood the details of your question, as the uses of TextBox1 and TextBox2 don't seem consistent, but here's what I read:
TextBox1 has the codes that the dictionary maps to a source directory.
TextBox2 has the path (from the dialog box) to the destination directory.
If that is correct, you're close. Some things to note:
I'm not sure why you have these two lines. They look like method definitions, but there's no implementation. I think you can remove them and use the equivalent System.IO calls:
public static string[] GetFiles(string mapping);
public static void Copy(string sourceFileName, string destFileName);
Directory.GetFiles(mapping) won't work, because mapping is a Dictionary<string, string>, not a string. You need to select the corresponding value (path) based on the key (numeric code) from TextBox1 and use that in the Directory.GetFiles() method.
File.Copy(Path.Combine(mapping, f)); destination; is an incorrect syntax and won't compile (should be File.Copy(Path.Combine(mapping, f), destination);. Additionally, you don't need to combine the source path and filename for the first argument, as GetFiles returns the path along with the filename (including extension). You will need to get the filename alone and combine it with the sourece path for the destination file, however. You can use Path.GetFileName to do this.
Try this code below - it addresses the issues noted above, with the assumption being that textBox1 is the source in mappings and textBox2 is the destination from the dialog window:
private void button2_Click(object sender, EventArgs e)
{
string source = textBox1.Text
string destination = textBox2.Text;
if (mappings.ContainsKey(source))
{
foreach (var f in Directory.GetFiles(source))
{
File.Copy(f, Path.Combine(destination, Path.GetFileName(f)));
}
}
else
{
// No key was found, how you handle it will be dictated by the needs of the application and/or users.
}
}
The above code does the following:
Gets the numeric value for the path of the source directory. This should correspond to one of the keys in the dictionary.
Gets the path for the destination directory based on the user selected value from the dialog box.
Checks to see if the key from textBox1 is present in the directory.
If it is, it gets the corresponding value for that key, which is the path for the source directory.
Next, it loops through the files in the specified source directory, copying each one in turn to the destination directory. Note that f (the file) is used as the source file for the first argument (as it contains the path as well, as Directory.GetFiles() returns both the path and the filename), and the destination directory is combined with the filename (retrieved by a call to Path.GetFileName). If f alone was used in the Path.Combine() method, you'd wind up with sourcePath\originalPath\filename.
If the key wasn't found, you ignore it or do something with it.
Again, the above code is based on my understanding of your question. If my understanding was less than correct, the principles I outlined should still be able to assist you in resolving the issue.
** EDIT **
Per the comments below, it sounds like all you need to do is flip the assignments for source and destination. textBox2 will contain the code that corresponds to a key in the mappings directory, which will give you the path of the source directory. textBox1 will contain the destination path. Like this:
string source = textBox2.Text
string destination = textBox1.Text;
The rest of the code stays the same.

ExtractToFile vs ExtractToDirectory

I have some code that is extracting a file to a directory. In the code below Global.fullpath is the full path to the file its self where as Global.path is the path to the directory. This code works:
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
AppendTextBox("Extracting Files...\r\n");
ZipFile.ExtractToDirectory(Global.fullPath, Global.path);
}
However I am trying to do an overwrite if any files exist so I have this code which doesn't seem to extract anything even when there are no existing files:
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
AppendTextBox("Extracting Files...\r\n");
using (ZipArchive archive = ZipFile.OpenRead(Global.fullPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
AppendTextBox("Extracting file: " + entry.FullName + "...\r\n");
entry.ExtractToFile(Path.Combine(Global.path, entry.FullName), true);
}
}
}
Based on the comments, if you're trying to extract a directory ExtractToFile() is not going to do what you expect. Directories can't be easily overwritten like files. I think you have two options:
Check if the directory specified by FullName exists, and delete it before writing.
Check if the directory specified by FullName exists, and then rename your folder you're going to write something like FullName = FullName + "_Copy";
Make sure you check if the combined path is a valid filename. The ExtractToFile method expects a path that ends with the filename, and some Zip archives can contain folders. In such a case, the entry.FullName property results in an invalid path.

How to navigate a few folders up?

One option would be to do System.IO.Directory.GetParent() a few times. Is there a more graceful way of travelling a few folders up from where the executing assembly resides?
What I am trying to do is find a text file that resides one folder above the application folder. But the assembly itself is inside the bin, which is a few folders deep in the application folder.
Other simple way is to do this:
string path = #"C:\Folder1\Folder2\Folder3\Folder4";
string newPath = Path.GetFullPath(Path.Combine(path, #"..\..\"));
Note This goes two levels up. The result would be:
newPath = #"C:\Folder1\Folder2\";
Additional Note
Path.GetFullPath normalizes the final result based on what environment your code is running on windows/mac/mobile/...
if c:\folder1\folder2\folder3\bin is the path then the following code will return the path base folder of bin folder
//string directory=System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString());
string directory=System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString();
ie,c:\folder1\folder2\folder3
if you want folder2 path then you can get the directory by
string directory = System.IO.Directory.GetParent(System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString()).ToString();
then you will get path as c:\folder1\folder2\
You can use ..\path to go one level up, ..\..\path to go two levels up from path.
You can use Path class too.
C# Path class
This is what worked best for me:
string parentOfStartupPath = Path.GetFullPath(Path.Combine(Application.StartupPath, #"../"));
Getting the 'right' path wasn't the problem, adding '../' obviously does that, but after that, the given string isn't usable, because it will just add the '../' at the end.
Surrounding it with Path.GetFullPath() will give you the absolute path, making it usable.
public static string AppRootDirectory()
{
string _BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
return Path.GetFullPath(Path.Combine(_BaseDirectory, #"..\..\"));
}
Maybe you could use a function if you want to declare the number of levels and put it into a function?
private String GetParents(Int32 noOfLevels, String currentpath)
{
String path = "";
for(int i=0; i< noOfLevels; i++)
{
path += #"..\";
}
path += currentpath;
return path;
}
And you could call it like this:
String path = this.GetParents(4, currentpath);
C#
string upTwoDir = Path.GetFullPath(Path.Combine(System.AppContext.BaseDirectory, #"..\..\"));
The following method searches a file beginning with the application startup path (*.exe folder). If the file is not found there, the parent folders are searched until either the file is found or the root folder has been reached. null is returned if the file was not found.
public static FileInfo FindApplicationFile(string fileName)
{
string startPath = Path.Combine(Application.StartupPath, fileName);
FileInfo file = new FileInfo(startPath);
while (!file.Exists) {
if (file.Directory.Parent == null) {
return null;
}
DirectoryInfo parentDir = file.Directory.Parent;
file = new FileInfo(Path.Combine(parentDir.FullName, file.Name));
}
return file;
}
Note: Application.StartupPath is usually used in WinForms applications, but it works in console applications as well; however, you will have to set a reference to the System.Windows.Forms assembly. You can replace Application.StartupPath by
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) if you prefer.
I use this strategy to find configuration and resource files. This allows me to share them for multiple applications or for Debug and Release versions of an application by placing them in a common parent folder.
Hiding a looped call to Directory.GetParent(path) inside an static method is the way to go.
Messing around with ".." and Path.Combine will ultimately lead to bugs related to the operation system or simply fail due to mix up between relative paths and absolute paths.
public static class PathUtils
{
public static string MoveUp(string path, int noOfLevels)
{
string parentPath = path.TrimEnd(new[] { '/', '\\' });
for (int i=0; i< noOfLevels; i++)
{
parentPath = Directory.GetParent(parentPath ).ToString();
}
return parentPath;
}
}
this may help
string parentOfStartupPath = Path.GetFullPath(Path.Combine(Application.StartupPath, #"../../")) + "Orders.xml";
if (File.Exists(parentOfStartupPath))
{
// file found
}
If you know the folder you want to navigate to, find the index of it then substring.
var ind = Directory.GetCurrentDirectory().ToString().IndexOf("Folderame");
string productFolder = Directory.GetCurrentDirectory().ToString().Substring(0, ind);
I have some virtual directories and I cannot use Directory methods. So, I made a simple split/join function for those interested. Not as safe though.
var splitResult = filePath.Split(new[] {'/', '\\'}, StringSplitOptions.RemoveEmptyEntries);
var newFilePath = Path.Combine(filePath.Take(splitResult.Length - 1).ToArray());
So, if you want to move 4 up, you just need to change the 1 to 4 and add some checks to avoid exceptions.
Path parsing via System.IO.Directory.GetParent is possible, but would require to run same function multiple times.
Slightly simpler approach is to threat path as a normal string, split it by path separator, take out what is not necessary and then recombine string back.
var upperDir = String.Join(Path.DirectorySeparatorChar, dir.Split(Path.DirectorySeparatorChar).SkipLast(2));
Of course you can replace 2 with amount of levels you need to jump up.
Notice also that this function call to Path.GetFullPath (other answers in here) will query whether path exists using file system. Using basic string operation does not require any file system operations.

Replacing delimiter characters in file path

I'm developing a C# web application in VS 2008. I let the user select an input file and then I store the file path in a string variable. However, it stores this path as "C:\\folder\\...". So my question is how do I convert this file path into single "\"?
Thank you guys for all your helps! Please forgive me as I am a newbie to ASP.NET development. This is more of my code in context. First I want to see if the directory exists. I guess I don't have to check this if I check if the file exists. But this should still work right? And currently my "path" string variable is not showing up the way I need it to. I'm not sure how to formulate this statement. Eventually I want to execute the ReadAllText statement (see the last line).
protected void btnAppend_Click(object sender, EventArgs e)
{
string fullpath = Page.Request.PhysicalPath;
string fullPath2 = fullpath.Replace(#"\\", #"\");
if (!Directory.Exists(fullpath2))
{
string msg = "<h1>The upload path doesn't exist: {0}</h1>";
Response.Write(String.Format(msg, fullpath2));
Response.End();
}
string path = "#" + fullpath2 + uploadFile.PostedFile.FileName;
if (File.Exists(path))
{
// Create a file to write to.
try
{
StreamReader sr = new StreamReader(path);
string s = "";
while(sr.Peek() > 0)
s = sr.ReadLine();
sr.Close();
}
catch (IOException exc)
{
Console.WriteLine(exc.Message + "Cannot open file.");
return;
}
}
if (uploadFile.PostedFile.ContentLength > 0)
{
inputfile = System.IO.File.ReadAllText(path);
Are you sure the problem is the backslashes? Backslash is an escape character in strings, such that if you were adding it in a string you have to type it as "\\" rather than "\". (if you don't use #) Note that the debugger frequently displays the string the way you would put it in code, with the escape characters, rather than direct.
According to the documentation, Page.Request.PhysicalPath returns the path to the specific file you are in, not the directory. Directory.Exists is only true if you give it a directory, not a file. Does File.Exists() return true?
For a start, calling fullpath.Replace() does nothing to fullpath; it returns a new string. Also, when your string literals have a \ (backslash) in them, you need to tell the compiler that you're not trying to use an escape sequence:
fullpath = fullpath.Replace(#"\\", #"\");
The # means "please treat this string literally (verbatim)". In other words, "when I say backslash, I mean backslash!"
See http://msdn.microsoft.com/en-us/library/362314fe.aspx.
Edit:
As LeBleu mentioned, you are calling Directory.Exists() on a full filepath. This won't work; you need to extract the directory part from the path. Try this:
if (!Directory.Exists(Path.GetDirectoryName(fullpath)))
{
...
}
You might want to consider replacing it with the Path.DirectorySeparatorChar rather than \ on the offchance that your code may end up running on a different platform one day (mono.net allows it to be run on linux or possibly more likely it might end up on some wierd mobile platform)
http://msdn.microsoft.com/en-us/library/system.io.path.directoryseparatorchar.aspx

Categories