Create folder structure with x number of files per folder
I've got a number of folders with over 500,000 items in each. I want to break these down into folders of 10,000 (or 50,000 or 5,000 or whatever the user defines.)
There's obviously something wrong in my logic, because as it currently stands it just moves all my files into the first folder it creates. I've tried playing around with different combinations of foreach and where, but no luck.
//Find all the files to move
string[] files = Directory.GetFiles(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
//Use selects the number of files to go in each folder
long h = long.Parse(tbFilePerFolder.Text);
//Used later
long i = 0;
//Used later
long j = 0;
//Get the number of folders to create
开发者_如何学C long k = files.Count() / h;
//Report back the number of files found
lblFilesFound.Text = "Files Found: " + files.Count();
//Create the necessary number of folders, plus 1 to pick up remainders
while (j <= k + 1)
{
Directory.CreateDirectory(textBox1.Text + @"\" + j.ToString("00000"));
lblFoldersCreated.Text = "Folders Created: " + j;
j++;
}
//Get each folder that's just been created
string[] folders = Directory.GetDirectories(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
//For each of those folders...
foreach (string folder in folders)
{
//While there is less than the requested number of folders...
while (i <= h)
{
//Get a list of the currently existing files
string[] files2 = Directory.GetFiles(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
//And iterate through it, moving to the defined directory
foreach (string file in files2)
{
File.Move(file, folder + @"\" + Path.GetFileName(file));
lblFilesMoved.Text = "Files Moved: " + i;
i++;
}
}
}
Your innermost loop also has to check i < h
:
foreach (string file in files2)
{
File.Move(file, folder + @"\" + Path.GetFileName(file));
lblFilesMoved.Text = "Files Moved: " + i;
i++;
if (i > h)
break;
}
I also note that you're calling Directory.GetFiles()
twice, and it is pretty expensive.
Consider re-using the first list, and maybe look for newcomers after you've moved.
If you can use Fx4 then there is Directory.EnumerateFiles()
that can make quite a difference on a folder with 500k files. But you'd have to adapt your code a lot more.
why don't you do sth like :
int j=0;
foreach (string filename in Directory.GetFiles(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly)
{
File.Move(filename , Path.Combine(textBox1.Text + j.ToString("0000"), Path.GetFileName(file));
j = (j + 1)%(k + 1);
}
In this case, consecutive files will be put in different folders. I don't know if it's important in your case.
The problem you have is the following code will never jump out the while loop until all files moved to your folder1:
while (i <= h)
{
string[] files2 = Directory.GetFiles(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
foreach (string file in files2)
{
File.Move(file, folder + @"\" + Path.GetFileName(file));
lblFilesMoved.Text = "Files Moved: " + i;
i++; //this will never jump out the while loop until all files moved to your folder1
}
}
instead, you should use following code: (as close to your original code as possible)
string[] files = Directory.GetFiles(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
long h = long.Parse(tbFilePerFolder.Text);
long i = 0;
long j = 0;
long k = files.Count() / h;
lblFilesFound.Text = "Files Found: " + files.Count();
while (j <= k + 1)
{
Directory.CreateDirectory(textBox1.Text + @"\" + j.ToString("00000"));
lblFoldersCreated.Text = "Folders Created: " + j;
j++;
}
string[] folders = Directory.GetDirectories(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly)
//do you really need to search again? or maybe you can just use files instead?
string[] files2 = Directory.GetFiles(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
ind d=0;
foreach (string file in files2)
{
string folder=folders[d];
while (i <= h)
{
File.Move(file, folder + @"\" + Path.GetFileName(file));
lblFilesMoved.Text = "Files Moved:" + i;
i++;
}
d++;
i=0;
}
I ended up going for a bit of everything above, so thanks very much for the ideas! (Also made use of Directory.EnumerateFiles as well.) I realise where the logic was going wrong and stopped calling GetFiles twice.
string[] folders = Directory.GetDirectories(textBox1.Text, "*.*", SearchOption.TopDirectoryOnly);
long d = 0;
long c = 0;
//And iterate through it, moving to the defined directory
while (d <= k)
{
while (i <= h)
{
try
{
string folder = folders[d];
string file = files[c];
File.Move(file, folder + @"\" + Path.GetFileName(file));
c++;
i++;
lblFilesMoved.Text = "Files Moved: " + i;
}
catch (Exception f)
{
MessageBox.Show(f.ToString());
}
}
d++;
i = 0;
精彩评论