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.
Related
I have a problem here and i need some help.
I work on a C# software in WPF, i have finished it, the program compile but do not run.
I've tried to search the problem using step by step run and it end on this line
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = Application.StartupPath + #"\Logs\" + DateTime.Now.DayOfYear + ".txt" };
and
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
and i got this error : " Attempt to read or write protected memory. This often indicates that another memory is corrupted "
that happen randomly during execution but mostly while running theses lines of code.
If you got a solution i'll take it !
The WPF Application class does not have a StartupPath property.
You could add System.Windows.Forms as project reference and use System.Windows.Forms.Application.StartupPath
Alternative:
string appPath = System.Reflection.Assembly.GetExecutingAssembly()
.GetModules()[0].FullyQualifiedName;
string appDir = Path.GetDirectoryName(appPath);
To debug your code with finer granularity, you could rewrite it:
var fileName = Application.StartupPath;
fileName += #"\Logs\";
fileName += DateTime.Now.DayOfYear
fileName += ".txt";
var logfile = new NLog.Targets.FileTarget("logfile");
logFile.FileName = fileName;
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.
I have the following code contained within a Script Task in SSIS 2012.
public void Main()
{
string inputDir = (string) Dts.Variables["User::InputDirectory"].Value;
string CSVFolder = (string) Dts.Variables["User::CSVFolder"].Value;
string XMLFolder = (string) Dts.Variables["User::XMLFolder"].Value;
string XLSXFolder = (string) Dts.Variables["User::XLSXFolder"].Value;
bool isXMLFolderEmpty = (bool) Dts.Variables["User::isXMLFolderEmpty"].Value;
bool isCSVFolderEmpty = (bool)Dts.Variables["User::isCSVFolderEmpty"].Value;
bool isXLSXFolderEmpty = (bool)Dts.Variables["User::isXLSXFolderEmpty"].Value;
string[] fileNames = Directory.GetFiles(#inputDir);
if (fileNames.Length > 0)
{
foreach (string inputFile in fileNames)
{
string FileExtension = Path.GetExtension(inputFile);
if (FileExtension == ".csv")
{
File.Move(inputDir + "\\" + inputFile, CSVFolder + "\\" + inputFile);
isCSVFolderEmpty = false;
}
else if (FileExtension == ".xlsx")
{
File.Move(inputDir + "\\" + inputFile, XLSXFolder + "\\" + inputFile);
isXLSXFolderEmpty = false;
}
else if (FileExtension == ".xml")
{
File.Move(inputDir + "\\" + inputFile, XMLFolder + "\\" + inputFile);
isXMLFolderEmpty = false;
}
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
However when I execute the Script task I am getting the following error:
DTS Script Task has encountered an exception in User code: Exception has been thrown by the target of invocation.
Can anybody point out what is going wrong? All of variable names are correct.
File.Move is incorrect
You might also be interested in the Path.Combine as it will more gracefully handle building paths than your blind string concatenation route.
Directory.GetFile indicates
Returns the names of files (including their paths) in the specified directory
so inputFile is already going to be in the form of C:\ssisdata\so_35605920\Foo.csv so your initial parameter to FileMove is simply inputFile
So really the challenge becomes changing the folder path out of the inputFile variable to the targeted one (CSV, XML, or XLSX). Lazy hack would be to call the string.replace method specifying the inputDir and using the new directory. I'd probably go with something a bit more elegant in case there's weirdness with UNC or relative paths.
Path.GetFileName will give me the file and extension. So using that + Path.Combine would yield the correct final path for our Move operation
Path.Combine(CSVFolder, Path.GetFileName(inputFile));
Thus
File.Move(inputFile, Path.Combine(CSVFolder, Path.GetFileName(inputFile)));
Visual studio is rather unhappy at the moment so pardon the lack of precision in the suggested code but if there are typos, you have the references to books online and the logic behind it.
Also, try/catch blocks are exceptionally helpful in defensive coding as will be testing to ensure the folders exist, there's no process with a lock on the file, etc.
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.