I have a program that mass creates directories based on a CSV file. It runs through the loop but then it hits an "invalid characters in path" I need a validation (or if statement) to validate the folderName first and if it's invalid -reports it in a log file, then just proceed with the next folder creation.
StreamWriter sw = new StreamWriter(targetdir + "log.txt");
try
{
string[] items = File.ReadAllLines(csv);
foreach (string item in items)
{
Directory.CreateDirectory(targetdir + item);
sw.WriteLine(item + " OK!");
}
MessageBox.Show("Done");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
sw.Close();
I'm not sure where to start. I feel like i have to add an "if else" but i'm not sure what to put. Thanks in advance.
The main change you need to do in your code is stopping concatenating together the variables that creates the destination folder and start using the Path.Combine method.
In your specific case you could use GetInvalidFileNameChars to have a list of characters not allowed to be part of a path or file name and then check if the current item contains any of those characters.
But there are other important changes to do.
First a StreamWriter is a disposable object and thus you should always create it inside a using statement to have a correct cleaup of its internal resources when you have done with it or even if an abnormal exception occurs.
Second, it is better to use File.ReadLines instead of loading all the lines in memory with ReadAllLines
char[] invalidChars = Path.GetInvalidFileNameChars();
string logFile = Path.Combine(targetdir, "log.txt");
try
{
using(StreamWriter sw = new StreamWriter(logFile))
{
foreach (string item in File.ReadLines(csv))
{
if(item.Any(x => invalidChars.Contains(x)))
sw.WriteLine(item + " BAD");
else
{
Directory.CreateDirectory(Path.Combine(targetdir,item));
sw.WriteLine(item + " OK!");
}
}
}
MessageBox.Show("Done");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Finally, I want to underline that in this context it is important to use GetInvalidFileNameChars and not GetInvalidPathChars because here we are checking the name of a folder. This name has the same rules used for files.
GetInvalidPathChars omits some characters that are valid in a path string like the \ or the ? and *. So for example GetInvalidPathChars doesn't have any issues with something like C:\Windows\System32\*.dll while this string contains characters not usable for a filename or for a single folder's name.
Related
I currently have this method that can successfully quote-enclose a single CSV file but I am trying to loop through 600+ CSV files in a directory and perform the Quote Enclose method on each one. I am unsure how to do this effectively. Any feedback is appreciated.
Below is my code:
public void QuoteEnclosingCSV()
{
string fileNamePath = Path.GetTempPath() + #"\Reports\*.csv";
var stringBuilder = new StringBuilder();
foreach (var line in File.ReadAllLines(fileNamePath))
{
stringBuilder.AppendLine(string.Format("\"{0}\"", string.Join("\",\"", line.Split(','))));
}
File.WriteAllText(string.Format(fileNamePath, Path.GetDirectoryName(fileNamePath)), stringBuilder.ToString());
}
string marFolder = Path.GetTempPath() + #"\Reports\";
var dir = new DirectoryInfo(marFolder);
foreach (var file in dir.EnumerateFiles("*.csv"))
{
QuoteEnclosingCSV();
}
Below is the error I'm receiving:
Illegal characters in path.
My first step in unraveling this conundrum would be to guess what the error message is trying to tell me. My first guess would be that it's trying to say that the path has illegal characters in it. Did you stop to check what characters were in the path that you get the error on?
I'll show you:
C:\Users\YoungStamos\AppData\Local\Temp\\Reports\*.csv
That's the path you pass to File.ReadAllLines(). The single argument to that method is a path to one single file. You can't have an asterisk (*) in a filename in Windows, because it's a wildcard.
What you seem to be trying to do is pass a parameter to QuoteEnclosingCSV(). In this loop, you carefully list each file, but you never tell QuoteEnclosingCSV() about any of them.
foreach (var file in dir.EnumerateFiles("*.csv"))
{
QuoteEnclosingCSV();
}
This is more like what you want:
public void QuoteEnclosingCSV(string fileNamePath)
{
var stringBuilder = new StringBuilder();
foreach (var line in File.ReadAllLines(fileNamePath))
{
stringBuilder.AppendLine(string.Format("\"{0}\"", string.Join("\",\"", line.Split(','))));
}
// I don't know what string.Format() is meant to do here; I'm guessing your guess is
// as good as mine, so I'm eliminating it.
//File.WriteAllText(string.Format(fileNamePath, Path.GetDirectoryName(fileNamePath)), stringBuilder.ToString());
File.WriteAllText(fileNamePath, stringBuilder.ToString());
}
And then call it like this:
string marFolder = Path.Combine(Path.GetTempPath(), "Reports");
var dir = new DirectoryInfo(marFolder);
foreach (var fileInfo in dir.EnumerateFiles("*.csv"))
{
QuoteEnclosingCSV( fileInfo.FullName );
}
I have a sync software, which loads CSV files from "Incoming" folder, processes them and then moves them to the "Archive" folder.
Today, I saw the following error with this sync software:
[23/06/2014 00:06:04 AM] : Failed to move file from
D:\IBI_ORDER_IMPORTER_FTP_SERVER\Template3\Fifty &
Dean\Incoming\5A040K___d6f1ca45937b4ceb98d29d0db4601bf4.csv to
D:\IBI_ORDER_IMPORTER_FTP_SERVER\Template3\Fifty &
Dean\Archive\5A040K___d6f1ca45937b4ceb98d29d0db4601bf4.csv - Could not
find a part of the path.
Here's a snippet taken out of the sync software, where the file is processed and moved:
public static void ProcessSingleUserFile(Int32 TemplateId, String ImportedBy, String FilePath)
{
// Always Rename File To Avoid Conflict
string FileName = Path.GetFileNameWithoutExtension(FilePath);
String NewFilePath = FilePath.Replace(FileName, Utils.RandomString() + "___" + FileName);
File.Move(FilePath, NewFilePath);
FilePath = NewFilePath;
// Log
SyncUtils.ConsoleLog(String.Format("Processing [ {0} as {1} ] By [ {2} ] On Template [ #{3} ]",
FileName + ".csv",
Path.GetFileName(FilePath),
ImportedBy,
TemplateId));
// Init
List<OrderDraft> myOrderDrafts = new List<OrderDraft>();
// Parsed Based On Template Id
if (TemplateId == Settings.Default.Multi_Order_Template_Id)
{
// Try Parse File
myOrderDrafts = Utils.ParseMultiImportFile(TemplateId, ImportedBy, FilePath, true);
}
else
{
// Try Parse File
myOrderDrafts.Add(Utils.ParseImportFile(TemplateId, ImportedBy, FilePath, true));
}
// Process Orders
foreach (OrderDraft myOrderDraft in myOrderDrafts)
{
/* code snipped */
}
// Archive File
File.Move(FilePath, FilePath.Replace("Incoming", "Archive"));
}
Any idea what this error means? and how to circumvent it?
I wrote a cut down version of the above to test this in a controlled environment and I am not getting the error with this code:
static void Main(string[] args)
{
try
{
string baseDir = #"C:\Users\Administrator\Desktop\FTP_SERVER\Template3\Fifty & Dean\Incoming\";
string[] filePaths = Directory.GetFiles(baseDir, "*.csv");
foreach (string filePath in filePaths)
{
// do some work here ...
// move file
string newFilePath = filePath.Replace("Incoming", "Archive");
File.Move(filePath, newFilePath);
Console.WriteLine("File successfully moved");
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
Console.ReadKey();
}
You need to include the checks to make sure that the paths exist at runtime and check the output, something very simple like:
if(!Directory.Exists(Path.GetDirectoryName(filePath)))
{
Console.WriteLine("filePath does not exist: " + filePath);
}
if(!Directory.Exists(Path.GetDirectoryName(newFilePath)))
{
Console.WriteLine("newFilePath does not exist: " + newFilePath);
}
File.Move(filePath, newFilePath);
The reason I am suggesting this method is due to a possibility that the paths momentarily become available or not under the multi-tasking OSs depending on a multitude of factors: network connectivity, permissions (pushed down by GPO at any time), firewall rules, AV exclusions getting blown away etc. Even running low on CPU or RAM may create issues. In short, you never know what exactly occurred when your code was running if you are only checking the paths availability after the fact.
Or if your issue is intermittent, you can try and catch the error and write information to some sort of a log similarly to below:
try
{
File.Move(filePath, newFilePath);
}
catch(Exception ex)
{
if(!Directory.Exists(Path.GetDirectoryName(filePath)))
{
Console.WriteLine("filePath does not exist: " + filePath);
}
if(!Directory.Exists(Path.GetDirectoryName(newFilePath)))
{
Console.WriteLine("newFilePath does not exist: " + newFilePath);
}
}
"Could not find a part of the path" exception could also thrown from File.Move if argument used was longer than MAX_PATH (260) in .NET Framework.
So I prepend the path I used with long path syntax before passing to File.Move and it worked.
// Prepend long file path support
if( !packageFile.StartsWith( #"\\?\" ) )
packageFile = #"\\?\" + packageFile;
See:
How to deal with files with a name longer than 259 characters?
I have this
Could not find a part of the path
happened to me when I
File.Move(mapfile_path , Path.Combine(newPath, mapFile));
. After some testing, I find out our server administrator has blocked any user application from writing to that directory in that [newPath]!
So, right click on that directory to observe the rights matrix on Security tab to see anything that would block you.
Another cause of DirectoryNotFoundException "could not find a part of the path" thrown by File.Move can be spaces at the end of the directory name. Consider the following code:
string destinationPath = "C:\\Folder1 "; //note the space on the end
string destinationFileNameAndPath = Path.Combine(destinationPath, "file.txt");
if (!Directory.Exists(destinationPath))
Directory.CreateDirectory(destinationPath);
File.Move(sourceFileNameAndPath, destinationFileNameAndPath);
You may expect this code to succeed, since it creates the destination directory if it doesn't already exist, but Directory.CreateDirectory seems to trim the extra space on the end of the directory name, whereas File.Move does not and gives the above exception.
In this circumstance, you can workaround this by trimming the extra space yourself, e.g. (depending on how you load your path variable, the below is obviously overkill for a hard-coded string)
string destinationPath = "C:\\Folder1 ".Trim();
What I am trying to do is to read in a file to a richTextBox automatically with the OnSelectedIndexChange method. There arent any errors, it just flat out doesnt work. Heres the code that I am working with
public void comboBox1_OnSelectedIndexChanged(object sender, EventArgs e)
{
string selectedPath = comboBox1.SelectedItem.ToString();
if (File.Exists(#"C:\\Mavro\\MavBridge\\" + selectedPath + "\\ " + "Comment" + ".txt"))
{
try
{
Thread.Sleep(0500);
System.IO.StreamReader textFile = new System.IO.StreamReader(#"C:\\Mavro\\MavBridge\\" + selectedPath + "\\ " + "Comment" + ".txt");
richTextBox1.Text = textFile.ReadToEnd();
textFile.Close();
}
catch
{
MessageBox.Show("Error: File cannot be opened!", "Error");
}
}
else
{
MessageBox.Show("No comment was found in this folder", "Alert");
}
}
Just for fun, lets have you try something. First, replace the following line:
if (File.Exists(#"C:\\Mavro\\MavBridge\\" + selectedPath + "\\ " + "Comment" + ".txt"))
with this:
if(File.Exists(string.Format("C:\\Mavro\\MavBridge\\{0}\\Comment.txt", selectedPath)))
It looks like you had an extra space ("\\ " + "Comment"), so I'm sure that's why it never hits this block of code. Also, anytime you have an object that needs to be closed/disposed, more often than not it implements IDisposable, meaning you should encapsulate the object within a using block:
Thread.Sleep(0500);
try
{
using(System.IO.StreamReader textFile = new System.IO.StreamReader(string.Format("C:\\Mavro\\MavBridge\\{0}\\Comment.txt", selectedPath)))
{
richTextBox1.Text = textFile.ReadToEnd();
}
}
catch
{
MessageBox.Show("Error: File cannot be opened!", "Error");
}
However, this can be simplified even further by bypassing the StreamReader entirely and using System.IO.File.ReadAllText instead:
richTextBox1.Text = System.IO.File.ReadAllText(string.Format("C:\\Mavro\\MavBridge\\{0}\\Comment.txt", selectedPath));
Well, one problem comes from the fact that you have:
#"C:\\Mavro\\MavBridge\\" + selectedPath + "\\ " + "Comment" + ".txt"
Since you are using a verbatim string (the # at the beginning), you do not need to put double slashes.
For the rest, make sure your file exists.
Later edit: also I am not sure if you copy/pasted in a rush or something like that, but did you actually put the catch block inside the try ?
1) What is the error you see?
2) Are you positive the file exists?
3) Are you positive the path created by your code is the path you are expecting?
4) Why are you sleeping the thread?
5) Why not just use File.ReadAllText?
6) File.Exists will return false if the code is running with permissions that do not have access to a file, even if the file does exist. Does the user your code is running as, have permissions?
true if the caller has the required permissions and path contains the
name of an existing file; otherwise, false. This method also returns
false if path is null, an invalid path, or a zero-length string. If
the caller does not have sufficient permissions to read the specified
file, no exception is thrown and the method returns false regardless
of the existence of path.
and
The Exists method returns false if any error occurs while trying to
determine if the specified file exists. This can occur in situations
that raise exceptions such as passing a file name with invalid
characters or too many characters, a failing or missing disk, or if
the caller does not have permission to read the file.
Get rid of # before each string. Your directory as it currently is uses actual double slashes instead of C:\Mavro\MavBridge. Use single slashes with \ or go with # at the beginning, but don't use both.
Also, I would strongly suggest using Path.Combine instead of concatenating pieces together like that.
Wondering how to best deal with a problem I am having with xsltransform. Long story short, everything works in my test environment, but it crashes when I run it on the server due to the filenames it tries to deal with, which are output from another program, over which I have no control.
For example. "4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml" a simple # would solve this, but it's actually running on a service, and this service gets all files of that type in the directory and processes them one by one.
string[] filepaths = Directory.GetFiles(path, Filetype);
I keep the file name variable in:
FileInfo f = new FileInfo(filepaths[i]);
But the method I use for the transform:
myXslTransform = new XslCompiledTransform();
myXslTransform.Transform(filename,OutputFileName);
Only accepts (String, String) and thus when it sees "4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml" it has a heart attack and cuts it off.
I was thinking save the original name, rename, remove whitespace, transform, and rename back. But I think there is a smarter way to handle it out there, just not sure where to look. Is there a way of telling C# to handle a variable as a literal? Or a different transform method that accepts these weird filenames with very bad naming conventions?
Any insight that helps would be great!
The error & exception message I recieve from the Eventvwr is
Cannot Translate
\\9g031\Export\4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml
OutputName = \\9g031\Export\done\4Copy (2) of Fed_Around_Six__TFVC020-12.mov.xml
XSL LOC = C:\CXS.xsl
System.IO.IOException: The specified path is invalid.
private void PreformTranslation(FileInfo FileName, String OutputFileName , String result)
{
try
{
XslCompiledTransform myXslTransform;
myXslTransform = new XslCompiledTransform();
myXslTransform.Load(XSLname);
EventLog.WriteEntry(FileName.ToString(), OutputFileName);
myXslTransform.Transform(FileName.Name,OutputFileName);
EventLog.WriteEntry("TranslationComplete");
if (File.Exists(path + result))
{
MoveVideoFiles(path + result, outputPath + result);
}
// Rename(OutputFileName, FileName, Out);
}
catch (Exception e)
{
EventLog.WriteEntry("Cannot Translate " + FileName + " OutputName = " + OutputFileName + " \r\n"+
"XSL LOC = " + XSLname + "\r\n" + e);
}
}
The default directory when running a service is something like "windows/system32" and this isn't the directory of the executable.
This is probably the reason the XML file isn't found.
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