Hi I am trying to write a simple program to copy a folder from one soure to many in parallel.
I am learning c# so have been trying to understand and change code examples, as i figured this the best way to learn somthing new.
The example below does not work as it only copies to the first destination in the destinationPaths
The stange thing is i have a simlar method to copy one file to many and this works everytime
have i missing something?? i would be greatful if someone could tell me why this is not working i am guessing that there maybe certain things you can't do in parallel
any advice would be great
public void CopyMultipleFolder(string sourceFilePath, params string[] destinationPaths)
{
if (string.IsNullOrEmpty(sourceFilePath)) MessageBox.Show("A source file must be specified.", "sourceFilePath");
else
{
if (destinationPaths == null || destinationPaths.Length == 0) MessageBox.Show("At least one destination file must be specified.", "destinationPaths");
else
{
try
{
FileIOPermission writeAccess = new FileIOPermission(FileIOPermissionAccess.AllAccess, destinationPaths);
foreach (string i in destinationPaths)
{
writeAccess.AddPathList(FileIOPermissionAccess.Write, i);
}
writeAccess.Demand();
NetworkCredential user = new NetworkCredential();
user.UserName = Properties.Settings.Default.username;
user.Password = Properties.Settings.Default.password;
if (user.Password.Length == 0 || user.UserName.Length == 0)
{
MessageBox.Show("No Username or password have been entered click username on menu bar to update", "Update Credentials");
}
else
{
Parallel.ForEach(destinationPaths, new ParallelOptions(),
destinationPath =>
{
if (sourceFilePath.EndsWith("*"))
{
int l = sourceFilePath.Length - 4;
sourceFilePath = sourceFilePath.Remove(l);
}
else
{
using (new NetworkConnection(destinationPath, user))
{
if (Directory.Exists(destinationPath + "\\" + foldername))
{
if (destinationPath.EndsWith("\\"))
{
DialogResult r = MessageBox.Show("Folder already Exists " + destinationPath + foldername + " Do You Want To overwrite All Files And Sub Folders", "Overwrite?", MessageBoxButtons.YesNo);
if (r == DialogResult.Yes)
{
PleaseWait.Create();
foreach (string dirPath in Directory.GetDirectories(sourceFilePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(sourceFilePath, destinationPath + "\\" + foldername));
foreach (string newPath in Directory.GetFiles(sourceFilePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourceFilePath, destinationPath+ "\\" + foldername), true);
list = list + destinationPath + foldername + Environment.NewLine;
}
else
{
}
}
else
{
DialogResult r = MessageBox.Show("Folder already Exists " + destinationPath + "\\" + foldername + " Do you Want to overwrite All Files And SubFolders", "Overwrite?", MessageBoxButtons.YesNo);
if (r == DialogResult.Yes)
{
PleaseWait.Create();
foreach (string dirPath in Directory.GetDirectories(sourceFilePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(sourceFilePath, destinationPath + "\\" + foldername));
//Copy all the files
foreach (string newPath in Directory.GetFiles(sourceFilePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourceFilePath, destinationPath + "\\" + foldername), true);
list = list + destinationPath + "\\" + foldername + Environment.NewLine;
}
else
{
}
}
}
else
{
PleaseWait.Create();
foreach (string dirPath in Directory.GetDirectories(sourceFilePath, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(sourceFilePath, destinationPath + "\\" + foldername));
//Copy all the files
foreach (string newPath in Directory.GetFiles(sourceFilePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourceFilePath, destinationPath + "\\" + foldername), true);
list = list + destinationPath +"\\"+foldername+ Environment.NewLine;
}
}
}
PleaseWait.Destroy();
});
MessageBox.Show("Folder Has Been Copied to " + list, "Folder Copied");
}
}
catch (UnauthorizedAccessException uae)
{
MessageBox.Show(uae.ToString());
}
}
}
}
You wrote you were learning C#. So, forget about parallel execution, because it unnecessarily makes your task more complicated. Instead, start by decomposing your problem into smaller parts. The code you posted is ugly, long, repeats a lot of logic many times, and hence it is and will be hard to read, debug, and maintain.
So, start by writing small functions for individual files. You need to create a set of folders in a destination folder. Hence write a function accepting a list of names and the destination folder. You need to determine the set of folders from a source folder. So write a function which does that. The combine those two functions together. And so on.
You will end up with a much cleaner, modifiable, reusable solution. Then it will be a lot easier to plug in parallel processing. Most likely, this will be for the sake of learning it, because it makes not much sense to parallelize your problem too heavily.
Related
I have a directory of files that contain both Word and PDF files. Some of the Word files in the directory have the same filename (minus extension) as the PDF files in the same directory. I have setup a simple C# winforms application to loop through the files and move the Word documents that have same name as PDF documents. Here's what I have so far. I'm not sure why this isn't working:
string[] filesWORD = Directory.GetFiles(#"c:\test\", "*.docx");
List<string> resultFiles = new List<string>();
foreach (var file in filesWORD)
{
var finalfile = file.Substring(0, file.LastIndexOf(".")); // removes everything after period in name.
resultFiles.Add(finalfile);
listBox1.DataSource = resultFiles.Distinct().ToList(); // placing the Word files in listBox1
}
string[] filesPDF = Directory.GetFiles(#"c:\test\", "*.pdf");
List<string> resultFilesPDF = new List<string>();
foreach (var file in filesPDF)
{
var finalfile = file.Substring(0, file.LastIndexOf("."));
resultFilesPDF.Add(finalfile);
listBox2.DataSource = resultFilesPDF.Distinct().ToList(); // placing the PDF files in listBox2
}
for (int i = 0; i < listBox1.Items.Count; i++)
{
//IF the WORD files in listBox1 match the PDF files in listBox2 -- move them to a new folder.
foreach (string files in listBox1.Items)
{
if (listBox1.Items == listBox2.Items)
{
//Get Filename
var filename = Path.GetFileName(files + ".docx");
//Move Files
File.Move(files + ".docx", #"c:\test2\" + "\\" + filename);
}
}
}
The final for loop is where the problem is, you can try this (need to add listbox for your case), you are comparing the wrong thing, also the outer for loop is not required.
foreach (var pdfFile in resultFilesPDF)
{
foreach (var wordFile in resultFiles)
{
if (wordFile == pdfFile)
{
//Get Filename
var filename = System.IO.Path.GetFileName(wordFile + ".docx");
//Move Files
File.Move(wordFile + ".docx", #"c:\test2\" + "\\" + filename);
}
}
}
Using Linq you can do it like, be aware that if you try to move the same file multiple times the Move method might blow up.
var sameNames = resultFiles.SelectMany(w => resultFilesPDF.Where(p => p == w));
sameNames.ToList().ForEach(file =>
{
File.Move(file + ".docx", #"c:\test2\" + "\\" + System.IO.Path.GetFileName(file + ".docx"));
});
looked all over and found plenty of stuff regarding this but none are using variables to form paths. What I need to do is move a folder, sub-folders and files to a new path on button click. So far none of what I found worked. At the moment, i'm getting no files or folders moved what so ever. The current solution I tried is from MSDN and tried to adapt it to my code. If you could correct the code and show me an example it would be great. I don't know what i'm doing wrong here. Here is the code:
private void CopyPartsToProject()
{
string sourcePath = (pathToQuotes + "/" + client_name.Text + "/" + quote_id.Text);
string targetPath = (pathToClient + "/" + client_name.Text + "/" + project_number.Text);
string sourceFile = sourcePath + "/" + "*.*";
string destinationFile = targetPath + "/" + "*.*";
System.IO.File.Move(sourceFile, destinationFile);
System.IO.Directory.Move(sourcePath, targetPath);
}
pathToQuotes and pathToClient are retreived from a MySQL database (from user input) in another method. The info is getting retreived without any problems and the paths are correct. If you could give me a hand it would be appreciated. Thanks.
You need a recursive method to achieve moving directories including all files and sub-directories:
private void moveDirectory(string sourcePath ,string targetPath)
{
if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
}
String[] files = Directory.GetFiles(sourcePath);
String[] directories = Directory.GetDirectories(sourcePath);
foreach (string f in files)
{
System.IO.File.Copy(f, Path.Combine(targetPath,Path.GetFileName(f)), true);
}
foreach(string d in directories)
{
// recursive call
moveDirectory(Path.Combine(sourcePath, Path.GetFileName(d)), Path.Combine(targetPath, Path.GetFileName(d)));
}
}
then the usage is like this:
private void CopyPartsToProject()
{
string sourcePath = (pathToQuotes + "/" + client_name.Text + "/" + quote_id.Text);
string targetPath = (pathToClient + "/" + client_name.Text + "/" + project_number.Text);
moveDirectory(sourcePath, targetPath);
}
New programmer working on a little file mover. Not sure why my while statement is not working. I am trying to have the program check if the file exists in the directory and if so, counter++ until it comes up with an original name e.g. 2018 Picture(45) and so on...
private void btnMove_Click(object sender, EventArgs e)
{
string sourcePath = #"C:\Users\David\Desktop\Personal Pictures & Videos\fromme";
string destinationPath = #"C:\Users\David\Desktop\Personal Pictures & Videos\practicefolder";
if (!Directory.Exists(destinationPath))
{
Directory.CreateDirectory(destinationPath);
}
string[] sourcefiles = Directory.GetFiles(sourcePath);
//looks at each file with its path attached.
int counter = 1;
foreach (string sourcefile in sourcefiles)
{
if (sourcefile.EndsWith(".jpeg"))
{
string destFile = Path.Combine(destinationPath, "2018 Picture" + "(" + counter + ")" + ".jpeg");
MessageBox.Show(destFile);
while (Directory.Exists(destFile))
{
counter++;
}
//renames and moves files from sourcePath to destinationPath
File.Move(sourcefile, destFile);
Incrementing just the counter does not automatically update the file name, which you check to exist for the break condition of the loop.
while(File.Exists(destFile))
{
counter++;
destFile = Path.Combine(destinationPath, $"2018 Picture({ counter }).jpeg");
}
We have to update the file name with the incremented counter every time.
The $ syntax for string concatenation is optional but makes the file name composition clearer.
Furthermore, Directory.Exists does not work for files. If you pass a file name that exists, it will still return false, because it checks for the directory flag on the file system entry.
Put the your code creating the filename inside the loop and the File.Move outside of the loop. You should also set an upper limit on "counter" so that you can't get stuck in an infinite loop. Then only do the File.Move if you don't hit the limit. Since you're going to be changing the name with every iteration, you should only display the messagebox after the new filename has been successfully found.
foreach (string sourcefile in sourcefiles)
{
if (sourcefile.EndsWith(".jpeg"))
{
bool bSuccess = true;
string destFile = Path.Combine(destinationPath, "2018 Picture" + "(" + counter + ")" + ".jpeg");
counter = 0;
while (File.Exists(destFile))
{
destFile = Path.Combine(destinationPath, "2018 Picture" + "(" + counter + ")" + ".jpeg");
counter++;
if(counter>1000)
{
MessageBox.Show("'Too many tries.' or what ever message you want to use.");
bSuccess = false;;
}
}
if(bSuccess)
{
MessageBox.Show(destFile);
File.Move(sourcefile, destFile);
}
}
I found several things to correct or improve.
private void btnMove_Click(object sender, EventArgs e)
{
string sourcePath = #"C:\Users\David\Desktop\Personal Pictures & Videos\fromme";
string destinationPath = #"C:\Users\David\Desktop\Personal Pictures & Videos\practicefolder";
//no need to check if the path exists. CreateDirectory() already does the right thing
Directory.CreateDirectory(destinationPath);
int counter = 0;
var sourcefiles = Directory.EnumerateFiles(sourcePath, "*.jpeg");
foreach (string sourcefile in sourcefiles)
{
bool tryAgain = true;
while (tryAgain)
{
try
{
counter++;
destFile = Path.Combine(destinationPath, $"2018 Picture ({ counter }).jpeg");
File.Move(sourcefile, destFile);
tryAgain = false;
MessageBox.Show(destfile);
}
catch(IOException ex)
{ //file I/O is one of the few places where exceptions might be okay for flow control
tryAgain = (counter < 10000);
}
}
}
}
private void btn_Backup_Click(object sender, EventArgs e)
{
List<DirectoryInfo> SourceDir = this.lbox_Sources.Items.Cast<DirectoryInfo>().ToList();
List<DirectoryInfo> TargetDir = this.lbox_Targets.Items.Cast<DirectoryInfo>().ToList();
foreach (DirectoryInfo sourcedir in SourceDir)
{
foreach (DirectoryInfo targetdir in TargetDir)
{
string dateString = DateTime.Now.ToString("MM-dd-yyyy_H.mm.ss");
string LogFileName = #"BackupLog_" + sourcedir.Name + #"_" + dateString + #".log";
string[] lines = { dateString + "\t" + sourcedir.FullName + "\t" + targetdir.FullName + "\t" + "COMPLETED" };
if (this.checkbox_zipfiles.Checked == true)
{
System.IO.Compression.ZipFile.CreateFromDirectory(sourcedir.FullName, targetdir.FullName + #"\BACKUP_" + sourcedir.Name + #"_" + dateString + #".zip");
System.IO.File.WriteAllLines(tbox_LogFiles.Text + #"\" + LogFileName, lines);
}
else
{
foreach (var file in sourcedir.GetFiles())
{
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(sourcedir.FullName, targetdir.FullName, true);
System.IO.File.WriteAllLines(tbox_LogFiles.Text + #"\" + LogFileName, lines);
}
}
}
}
}
I need to exclude certain files from the backup (like .txt .docx)
I am using a list on my Form to add those exceptions.
I will also need to exclude certain Files and Folders but I think I can do that if I know how to do this.
private void btn_AddFileTypeException_Click(object sender, EventArgs e)
{
Form_FileTypeExceptions frm = new Form_FileTypeExceptions(new FileException());
if (frm.ShowDialog() == DialogResult.OK)
{
this.lbox_FileTypeExceptions.Items.Add(frm.Exception);
}
}
Any ideas please?
From form where you're setting extensions to be excluded fill list of strings that will contain extensions to skip, something like this:
List<string> extensionsToSkip = new List<string>();
extensionsToSkip.Add(".txt");
extensionsToSkip.Add(".docx");
//etc...
in your inner loop, change foreach loop from
foreach (var file in sourcedir.GetFiles())
into this
foreach (var file in sourcedir.GetFiles()
.Where(f => !extensionsToSkip.Contains(f.Extension)).ToList())
as you can see, when you get file collection with GetFiles it will be filtered to exclude extensions specified in extensionsToSkip list.
before that mentioned loop, test if you're getting right number of files by observing there two lists (just for test):
var originalList = sourcedir.GetFiles();
var filteredList = sourcedir.GetFiles().Where(f => !extensionsToSkip.Contains(f.Extension)).ToList();
With this asp net page upload file in C# I need check for duplicates files.
I accept 3 files in upload on the server.
This code worked and the duplicates file are not uploaded, but the alert popup is open only for the first duplicate file send to upload even when duplicates are more.
What's the problem ?
My code below, thank you in advance.
if (File.Exists(upload.FileName))
{
DirectoryInfo objDir = new DirectoryInfo(Server.MapPath("\\images\\"));
FileInfo[] objFI = objDir.GetFiles("*.*");
int iFileCnt = 0;
if (objFI.Length > 0)
{
foreach (FileInfo file in objFI)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "Msg", "alert('This file exists " + upload.FileName + "');", true);
iFileCnt += 1;
}
}
}
Change "Msg" to the the "Msg" + iFileCnt. This changes the key for every iteration.
Page.ClientScript.RegisterStartupScript(this.GetType(), "Msg" + iFileCnt, "alert('This file exists " + file.Name + "');", true);
Now alert execute more then once in loop.
How about something like this?
List<string> Filenames = new List<string>()
{
"File1.jpg",
"File2.jpg"
//etc.
};
foreach(string s in Filenames)
{
Upload(s);
}
private void Upload(string filename)
{
string directory = #"\\path\\to\\directory";
string fullpath = string.Format(#"{0}\{1}", directory, filename);
if(File.Exists(fullpath))
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "Msg", "alert('This file exists " + filename + "');", true);
}
}