I spent almost three days with this below, so I finally ended up here.
I have a function (from MSDN) which copies a folder with it's every file and subfolder. First it copies the main folder's files, then calls itself on each subfolder.
Here it is:
private void DirectoryCopy(string sourceDirName, string destDirName)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = System.IO.Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// Copying subdirectories and their contents to new location.
foreach (DirectoryInfo subdir in dirs)
{
string temppath = System.IO.Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
The problem is that it could take a long time therefore I tried to use BackgroundWorker, but I don't know how to place it in it's DoWork event.
If I place the first DirectoryCopy call in the DoWork event, can't handle the Cancel event:
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
DirectoryCopy(sourcePath, destPath, true);
}
sourcePath and destPath are members of my class.
Any tips how can I handle the worker's Cancel event in the DirectoryCopy?
Or any other tips to make it working?
Thanks!
Although I haven't worked with BackgroundWorker yet, looking at your question - a quick ( might be ill-logical ) suggestion would be to pass DoWorkEventArgs e inside the DirectoryCopy method
like
DirectoryCopy (sourcePath, destPath, true, worker , e)
where BackgroundWoker worker , DoWorkEventArgs e
and handle it whatever way you want it inside.
Example :
if (worker.CancellationPending)
{
// your code
e.Cancel = true;
}
Hope this helps!
The best and easiest approach here is to use Directory.EnumerateDirectories(,,).
This remove the recursion from your code and makes it easier to stop.
foreach(var dir in Directory.EnumerateDirectories(sourceDir, "*.*", SearchOption.AllDirectories)
{
foreach(var file in Directory.EnumerateDirectories(dir, "*.*")
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
// copy file
}
}
Related
Good day,
I have a problem regarding moving the file to other folder.
the scenario is this. Every time i put in the main folder it will automatically copy the file into folder 2.
(TAKE NOTE AUTOMATICALLY CHECK IF THE FOLDER HAS A FILE THEN COPY THE FILE TO FOLDER 2)
this is my code
string[] files = System.IO.Directory.GetFiles(filepath, "*exp.zip", System.IO.SearchOption.TopDirectoryOnly);
if (files.Length < 1)
{
MessageBox.Show("No File");
}
else
{
// COPY THE FILE TO THE OTHER FOLDER
}
THANK YOU GUYS.
I think what you need is an automatic trigger when any zip file is placed in folder than it automatically get copied.
MSDN:
FileSystemWatcher listens to the file system change notifications and
raises events when a directory, or file in a directory, changes.
Check msdn for more detail.
What you need:
FileSystemWatcher fileWatcher;
private void watch()
{
fileWatcher = new FileSystemWatcher();
fileWatcher.Path = path;
fileWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
fileWatcher.Filter = "*.zip";
fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
//Copies file to another directory.
}
It's easy,just need to check for the file extension in the filename :
private void Test()
{
var Folder = "FolderPathHere";
var FilesCount = GetFiles(Folder);
foreach (var file in FilesCount)
{
if (file.Contains("zip"))
{
////ur moving file code here
}
}
}
string fileExtension = "*.zip";//file type
string[] txtFiles = Directory.GetFiles(sourcePath, fileExtension);//find all zip files
foreach (var item in txtFiles)//move all zip files
{
if (File.Exists(item)
{
File.Move(source, destination + item.GetFileName(source));//move the file into destination
}
else
{
File.Move(source, destination2 + item.GetFileName(source));//move the file into destination
}
}
I wrote this code in c# for change location of folder and all sub-folders of this folder. I want to change name of all folders when copy it to destination. for example I want to change name from 1 to .... . how should I change my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
namespace Folder
{
class clssMoveFolder
{
string temppath;
public string StrtxtSource;
public string destDirName;
public void Directorycopy(string sourceDirName, string destDirName, bool cutSubDirs, string strExtension)
{
try
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
// If the source directory does not exist, throw an exception.
if (!dir.Exists)
{
throw new DirectoryNotFoundException("Source directory does not exist or could not be found: " + sourceDirName);
}
FileInfo[] files = dir.GetFiles();
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
//Get the file contents of the directory to copy.
for (int a = 0; a < files.Length; ++a)
{
// Create the path to the new copy of the file.
if (files[a].Extension == "."+strExtension )
{
temppath = Path.Combine(destDirName, files[a].Name);
files[a].MoveTo(temppath);
}
else if (files[a].Extension == strExtension)
{
temppath = Path.Combine(destDirName, files[a].Name);
files[a].MoveTo(temppath);
}
else if (strExtension == "AllFiles")
{
temppath = Path.Combine(destDirName, files[a].Name);
files[a].MoveTo(temppath);
}
else
files[a].Delete();
dir.Refresh();
}
FileInfo[] filesCheck = dir.GetFiles();
if (dirs.Length == 0 && filesCheck.Length == 0 && dir.Name != StrtxtSource)
{
dir.Delete();
}
// If copySubDirs is true, copy the subdirectories.
if (cutSubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
// Copy the subdirectories.
string temppath= Path.Combine(destDirName, subdir.Name);
Directorycopy(subdir.FullName, temppath,cutSubDirs,strExtension);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
}
}
If you just want to rename a file after copying it you could instead directly copy it under a different name. E.g. instead of copying a.txt and rename it to b.txt afterwards, you could just copy the original a.txt as b.txt to the destination directory.
Renaming can be done by using the File.Move method.
File.Move("a.txt", "b.txt");
If you want to be able to do this even if someone else copies files into a directory (e.g. by using the windows explorer or files written by another application), you may want to take a closer look at the FileSystemWatcher. You can use it to monitor changes in a specified directory (optionally including it's subdirectories) and react on these changes.
...
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = #"D:\SomeTestDirectory";
watcher.Filter = "*.*";
watcher.NotifyFilter = NotifyFilters.FileName; // Trigger only on events associated with the filename
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true; // Starts the "watching"
...
private static void OnChanged(object source, FileSystemEventArgs e)
{
// Do whatever you want here, e.g. rename the file.
Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
}
I have bunch of text files in C:\Source folder.
I want to copy all the files to MyData folder place across the C:\ drive.
Please let me know the approach in C#, I am thinking it will be a recursive one.
I know how to copy the file from one location to another.
I want to get the approach to get all the folders/Directories with name "MyData" across the C:.
And the folder "MyData" is at multiple location. So I want to copy the files to all the places.
This answer is taken directly from MSDN here: http://msdn.microsoft.com/en-us/library/bb762914.aspx
using System;
using System.IO;
class DirectoryCopyExample
{
static void Main()
{
// Copy from the current directory, include subdirectories.
DirectoryCopy(".", #".\temp", true);
}
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
}
You can make use of FileSystemWatcher class in System.IO namespace.
public void FolderWatcher()
{
FileSystemWatcher Watcher = new System.IO.FileSystemWatcher();
Watcher.Path = #"C:\Source";
Watcher.Filter="*.txt";
Watcher.NotifyFilter = NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName;
Watcher.Created += new FileSystemEventHandler(Watcher_Created);
Watcher.EnableRaisingEvents = true;
}
void Watcher_Created(object sender, FileSystemEventArgs e)
{
File.Copy(e.FullPath,"C:\\MyData",true);
}
If you really don't know where to start, I suggest taking a look at this question that was asked a while back. There are plenty of examples and links to get you started.
Hi I am creating a windows service to watch certain directories to see if the size of the directory is reaching its limit.
I have created a file system watcher as follows:
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = dirPaths[i].ToString();
watcher.NotifyFilter = NotifyFilters.Size;
watcher.EnableRaisingEvents = true;
watcher.Changed += new FileSystemEventHandler(OnChanged);
and
private void OnChanged(object source, FileSystemEventArgs e)
{
try
{
string directory = new DirectoryInfo(e.FullPath).Parent.FullName;//gettting the directory path from the full path
float dirSize = CalculateFolderSize(directory);
float limitSize = int.Parse(_config.TargetSize);//getting the limit size
if (dirSize > limitSize)
{
eventLogCheck.WriteEntry("the following path has crossed the limit " + directory);
//TODO: mail sending
}
}
catch (Exception ex)
{
eventLogCheck.WriteEntry(ex.ToString());
}
}
CalculateFolderSize checks the size of all the files and subdirectories in the drive.
Now this works fine when I add a file to the directory e.g. a .xls, .txt, etc. file but if I add a folder to the directory it does not trigger the OnChanged event??
if I enable:
watcher.IncludeSubdirectories = true;
it does trigger the Onchanged event but in this case it only checks the subdirectory and not the entire directory.
Please can someone tell me how I can get this to work such that when I copy a folder to the directory being watched it triggers the Onchanged event and calculates the new size of the directory.
my CalculateFolderSize function is as follows if this helps:
//function to calculate the size of the given path
private float CalculateFolderSize(string folder)
{
float folderSize = 0.0f;
try
{
//Checks if the path is valid or not
if (!Directory.Exists(folder))
{
return folderSize;
}
else
{
try
{
foreach (string file in Directory.GetFiles(folder))
{
if (File.Exists(file))
{
FileInfo finfo = new FileInfo(file);
folderSize += finfo.Length;
}
}
foreach (string dir in Directory.GetDirectories(folder))
{
folderSize += CalculateFolderSize(dir);
}
}
catch (NotSupportedException ex)
{
eventLogCheck.WriteEntry(ex.ToString());
}
}
}
catch (UnauthorizedAccessException ex)
{
eventLogCheck.WriteEntry(ex.ToString());
}
return folderSize;
}
You're using the folder path provided by the FileSystemEventArgs so that will be the folder that has changed. Instead, create an object for each directory root that you are monitoring and, inside it, store the root path and use that instead of the EventArgs.
You may find an easy way to create this object is just to use a lambda function for the event handler as follows. This effectively wraps up the path from the outer scope into a different object for each path you are monitoring.
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = dirPaths[i].ToString();
watcher.NotifyFilter = NotifyFilters.Size;
watcher.EnableRaisingEvents = true;
watcher.Changed += delegate (object source, FileSystemEventArgs e)
{
float dirSize = CalculateFolderSize(watcher.Path); // using the path from the outer scope
float limitSize = int.Parse(_config.TargetSize);//getting the limit size
if (dirSize > limitSize)
{
eventLogCheck.WriteEntry("the folloing path has crossed the limit " + directory);
//TODO: mail sending
}
};
I want to display the path of each file when a button is pressed.
What I have right now is a function that iterates through a folder and displays the paths, but only when the function is finished:
public void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
try
{
var fileEntries = Directory.GetFiles(targetDirectory);
foreach (var fileName in fileEntries)
{
ProcessFile(fileName);
}
}
catch (Exception e){}
// Recurse into subdirectories of this directory.
try
{
var subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory);
}
catch (Exception e){}
}
public void ProcessFile(string path)
{
myListBox.Items.Add(path);
}
This means that I have to wait before I can do something else.
How can I display the path of a file instantly when the function is running, so i don't have to wait before the function is finished, getting all the paths before displaying in the listbox?
I don't remember where I came across this piece of code, but if you modify your ProcessFile method to something like this it will update your UI after each item is added to your list.
public void ProcessFile(string path)
{
myListBox.Items.Add(path);
myListBox.ScrollIntoView(myListBox.Items[myListBox.Items.Count-1]);
Dispatcher.Invoke(new Action(delegate { }), DispatcherPriority.Background);
}
I think I remember reading somewhere that this "hack" is not recommended due to a number of other problems that might occur, but I can't remember what it was or where I read it. It does the job however.
Maybe someone else can enlighten us about what these problems are...
This makes your method run on another thread:
public void StartProcessThread(string targetDirectory)
{
Thread T = new Thread(new ParameterizedThreadStart(ProcessDirectory));
T.Start(targetDirectory);
}
public void ProcessDirectory(object objTargetDirectory)
{
string targetDirectory = (string)objTargetDirectory;
// Process the list of files found in the directory.
try
{
var fileEntries = Directory.GetFiles(targetDirectory);
foreach (var fileName in fileEntries)
{
ProcessFile(fileName);
}
}
catch (Exception e){}
// Recurse into subdirectories of this directory.
try
{
var subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach (string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory);
}
catch (Exception e){}
}
public void ProcessFile(string path)
{
Dispatcher.Invoke(new Action(() => {
myListBox.Items.Add(path);
}));
}