#c# #system.io.file
#c# #system.io.file
Вопрос:
Я столкнулся с проблемой копирования файлов / каталогов. Боролся почти целый день. Я должен скопировать из корневого каталога файлы и его каталоги с файлами и вложенными каталогами. На самом деле, я кое-что сделал. Однако каждый раз, когда я запускаю ошибку stackoverflow.
abstract class SystemOperations {
public virtual void SearchFiles() { }
public virtual void SearchDirectories() { }
public abstract void CreateDirectory(string DIR);
public abstract void CloneContent(string DIR);
public abstract void CreateJSON(string DIR);
public void ExecuteCopying(string DIR) {
CreateDirectory(DIR);
CloneContent(DIR);
CreateJSON(DIR);
}
}
class FileOperations : SystemOperations {
DirectoryInfo _MainPath;
public DirectoryInfo MainPath {
get { return _MainPath; }
set { _MainPath = value; }
}
public FileOperations(DirectoryInfo MainPath) {
this.MainPath = MainPath;
}
#region Unnecessary for current task
public override void SearchFiles() {
string path = "";
FileInfo[] files = MainPath.GetFiles();
foreach (FileInfo file in files) {
path = file.Name;
}
}
public override void SearchDirectories() {
string path = "";
DirectoryInfo[] directories = MainPath.GetDirectories();
foreach (DirectoryInfo directory in directories) {
path = directory.Name;
}
}
#endregion
public override void CreateDirectory(string DIR) {
string newFolder = Path.Combine(MainPath "", DIR);
Directory.CreateDirectory(newFolder);
}
public override void CloneContent(string DIR) {
foreach (var directory in Directory.GetDirectories(MainPath "")) {
string dir = Path.GetFileName(directory);
CloneContent(Path.Combine(MainPath "", dir));
}
foreach (var file in Directory.GetFiles(MainPath "")) {
File.Copy(file, Path.Combine(MainPath "", Path.GetFileName(file)), true);
}
}
public override void CreateJSON(string DIR) {
if (!Directory.Exists(DIR)) {
var asd = new DirectoryInfo(DIR);
}
}
}
class Program {
static void Main() {
SystemOperations task = new FileOperations(new DirectoryInfo(@"D:\LAK"));
task.ExecuteCopying("COPY");
}
}
Итак, функция CloneContent должна копировать в каждый каталог / вложенные файлы. Но его рекурсивная функция и, как я писал выше, я бегу к ошибке. И не знаю, как это исправить. Спасибо!
Комментарии:
1. При использовании рекурсии вам нужно предложение break out. Должен быть сценарий, в котором вы не выполняете рекурсию. Вот пример: geeksforgeeks.org/program-for-nth-fibonacci-number . В этом случае вы выходите из функции, если введенное значение меньше 2.
2.
foreach (var directory in Directory.GetDirectories(MainPath ""))
должно быть...GetDirectories(DIR))
3. Ваши
Search...
функции не имеют смысла, они ничего не делают.MainPath ""
то жеMainPath
самое, что и . Также_mainPath
можно удалить, сделав его автоматическим свойством.4. @Charlieface Нет,
MainPath ""
это то жеMainPath.ToString()
самое, что и (MainPath
являетсяDirectoryInfo
экземпляром). Однако следует отметить, что в документации указано, чтоFullName
вместо этого следует использовать свойство.5. Однако @Charlieface
MainPath
— это не строка. ЭтоDirectoryInfo
объект. Если бы вы это сделалиDirectory.GetDirectories(MainPath)
, вы бы получили ошибку компиляции. Вам нужно сделатьDirectory.GetDirectories(MainPath.FullName)
илиDirectory.GetDirectories(MainPath.ToString())
или, как они это делали,Directory.GetDirectories(MainPath "")
. Еще лучше, поскольку этоDirectoryInfo
объект:MainPath.GetDirectories()
Ответ №1:
Существует какая-то проблема с тем, как вы пытаетесь определить, в каком каталоге вам нужно искать дальше, использование MainPath мне кажется неправильным.
Лично я также всегда предпочитаю иметь вторичное условие остановки, чтобы избежать исключения StackOverflowException, например, maxrunCount, которое я использую ниже.
Если вы хотите рекурсивный поиск в каталоге, вам следует переписать свой код на что-то вроде
void Main()
{
string MainPath = "D:\LAK";
// unless your directory is actually named LAK:) you should use either @"D:LAK" or "d:\LAK"
CloneContent(MainPath,1000);
}
public void CloneContent(string directoryToSearch, int maxrunCount)
{
if(maxrunCount==0)
return;
System.Diagnostics.Debug.Print(directoryToSearch);
string[] directories = null;
try
{
directories = Directory.GetDirectories(directoryToSearch);
}
catch(UnauthorizedAccessException ex) {
System.Diagnostics.Debug.Print($"No access to dir {directoryToSearch}");
directories = new string[0];
}
// ensure you have access to the current directoryToSearch
foreach (var directory in directories)
{
CloneContent(directory,--maxrunCount);
}
System.Diagnostics.Debug.Print($"cloning {directoryToSearch}");
// .... do the actual cloning here,
// you will end up here when there are no more subdirectories on the current branch
}
Ответ №2:
Чтобы рекурсивный метод работал, у него должно быть хотя бы одно условие «выхода» — точка, в которой он выполнил свою работу и может разматывать стек. В нашем случае это было бы, когда больше нет каталогов или файлов для копирования из источника в пункт назначения.
Один из способов написания этого метода — использовать исходный каталог и каталог назначения, а затем он может рекурсивно вызывать себя для каждого подкаталога:
public static void CloneContent(string sourceDir, string destDir)
{
// If the source directory doesn't exist, return
if (!Directory.Exists(sourceDir)) return;
// Create destination if needed
Directory.CreateDirectory(destDir);
// Copy files from this directory to the new path
foreach (string file in Directory.GetFiles(sourceDir))
{
File.Copy(file, Path.Combine(destDir, Path.GetFileName(file)));
}
// Recursively call this method for each sub directory
foreach (string subDir in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(subDir);
string newSource = Path.Combine(sourceDir, dirName);
string newDest = Path.Combine(destDir, dirName);
CloneContent(newSource, newDest);
}
}