SSIS Script Task for moving files based on their file extension - c#

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.

Related

Writing a report of cpp file in txt format with same name as file name

I am reading files from a directory and reading all text and generating reports separately for each file. I want report name same as file name.
I have tried to get file name but when I pass it to reporting module it gives exception error.
string path = "D:\\AssertCount\\";
foreach (string sFile in Directory.EnumerateFiles(path))
{
assertCount=0;
reportingCounter++;
string[] files = Directory.GetFiles(path);
string fileName = files[reportingCounter];
}
ReportWriting(totalWords, assertCount,fileName);
here is complete report writing module
public static void ReportWriting(int totalWords, int assertCount,string fileName)
{
StreamWriter file = new StreamWriter("D:\\AssertCount\\Reports\\"+fileName+".txt");
file.Write("TotalWords = " + totalWords);
file.Write("\nAasserts = " + assertCount);
file.Write("\nOccurence of assert keyword in code is " + assertPercentage + " % ");
file.Close();
}
followin exception occurs
System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect : 'D:\AssertCount\Reports\D:\AssertCount\testData2.cpp.txt''
The issue is that Directory.EnumerateFiles() and Directory.GetFiles() return full paths, not file names. You could try replacing
string fileName = files[reportingCounter];
with
string fileName = Path.GetFileNameWithoutExtension(files[reportingCounter]);
to turn the full path into just the file name, without the extension (since you add on ".txt" later).
Alternatively, you're already enumerating the files in the directory with the foreach, so why not just use sFile?
foreach (string sFile in Directory.EnumerateFiles(path))
{
assertCount=0;
string fileName = Path.GetFileNameWithoutExtension(sFile);
ReportWriting(totalWords, assertCount,fileName);
}
You're duplicating the path:
'D:\AssertCount\Reports\D:\AssertCount\testData2.cpp.txt' (It should be just 'D:\AssertCount\testData2.cpp.txt'
The variable fileName already includes the full path to the resource (not only the file name). So you could just delete "D:\AssertCount\Reports\" from the creation of the StreamWriter object. The code would be like this
public static void ReportWriting(int totalWords, int assertCount,string fileName)
{
StreamWriter file = new StreamWriter(fileName+".txt");
file.Write("TotalWords = " + totalWords);
file.Write("\nAasserts = " + assertCount);
file.Write("\nOccurence of assert keyword in code is " + assertPercentage + " % ");
file.Close();
}

Could not find a part of the path C# asp.net when I generated user session folder in particular directory

string UserFolder = Session["Username"].ToString();
if (!Directory.Exists("~/MisReports/EmailAttachment/"+UserFolder))
{
Directory.CreateDirectory("~/MisReports/EmailAttachment/"+UserFolder);
}
filePathE = Server.MapPath("~/MisReports/EmailAttachment/" + UserFolder + "/");
filePathE = filePathE + a + ".pdf";
bool isExist = File.Exists(filePathE);
if (isExist)
{
File.Delete(filePathE);
}
report.ExportToDisk(ExportFormatType.PortableDocFormat, filePathE);
I get the error
Could not find a part of the path
if (!Directory.Exists("~/MisReports/EmailAttachment/"+UserFolder))
{
Directory.CreateDirectory("~/MisReports/EmailAttachment/"+UserFolder);
}
in this area code does not enter if check although that the folder has not been created
The ~ is probably not evaluated if you are running on Windows. Windows is not Unix. Read up on Path.Combine, Environment.GetFolderPath and Environment.SpecialFolder on MSDN. You should build a path with code like
string directoryName = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments), "MisReports/EmailAttachment", UserFolder);

Trouble specifying destination filename for use in FileInfo.Copy example from MSDN

I'm using two DateTimePickers to specify a date range, then I'm using a CheckedListBox to specify some strings for filenames with wildcards to enumerate in each day's subdirectory contained within a system environment variable path. I want to copy from that source to a destination using FileInfo.Copy.
I have my code already creating the necessary directories. But I'm having trouble specifying the destination filenames -- they are not being specified at all with how I have this written.
I was thinking of using regular expressions, but after some digging I found this MSDN article that seems to do what I want already. I think I need to alter my code in order to use it. I could use some assistance fitting what I already have into what MSDN shows in its example.
I have been on this part of my program for a month now, which has led me to learn quite a bit about c#, parallel programming, async, lambda expressions, background workers, etc. What seems should be simple has become a big rabbit hole for me. For this question I just need a nudge in the right direction, and I will greatly appreciate it!
Here is my code as it stands:
private async void ProcessFiles()
{
// create a list of topics
var topics = topicsBox.CheckedItems.Cast<string>().ToList();
// create a list of source directories based on date range
var directories = new List<string>();
var folders = new List<string>();
for (DateTime date = dateTimePicker1.Value.Date;
date.Date <= dateTimePicker2.Value.Date;
date = date.AddDays(1))
{
directories.Add(_tracePath + #"\" + date.ToString("yyyy-MM-dd") + #"\");
folders.Add(#"\" + date.ToString("yyyy-MM-dd") + #"\");
}
// create a list of source files to copy and destination
// revise based on https://msdn.microsoft.com/en-us/library/kztecsys.aspx?f=255&MSPPError=-2147217396
foreach (var path in directories)
{
var path1 = path;
try
{
foreach (var files2 in folders)
{
// create the target directory
var destPath = textBox1.Text + #"\" + textBox4.Text + files2;
Console.WriteLine("Target directory is {0}", destPath);
Console.WriteLine("Destination filename is {0}", files2);
foreach (var files in topics)
{
foreach (string sourcePath in Directory.EnumerateFiles(path1, files + "*.*", SearchOption.AllDirectories))
{
// copy the files to the temp folder asynchronously
Console.WriteLine("Copy {0} to {1}", sourcePath, destPath);
Directory.CreateDirectory(sourcePath.Replace(sourcePath, destPath));
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
So sourcePath contains the source path and filename. You can easily construct the destination path from that, like so:
// Get just the filename of the source file.
var filename = Path.GetFileName(sourcePath);
// Construct a full path to the destination by combining the destination path and the filename.
var fullDestPath = Path.Combine(destPath, filename);
// Ensure the destination directories exist. Don't pass in the filename to CreateDirectory!
Directory.CreateDirectory(destPath);
Then you can copy the file (synchronously) like this:
File.Copy(sourcePath, fullDestPath);

System.IO.File.Move error - Could not find a part of the path

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();

Handling XSLT file names c#

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.

Categories