1

所以我有一些代码可以递归地创建目录并分别下载文件夹中的文件。

这是代码:

public class Program
    {
        static void UploadDownloadProgress(Object sender, FileDataTransferEventArgs e)
        { 
            // print a dot
            Console.WriteLine("Downloading");
            Console.WriteLine(".");
            // it's ok to go forward
            e.Cancel = false;
        } 

        public static void DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, string targetDir, string sourceDir)
        {           

            foreach (ICloudFileSystemEntry fsentry in remoteDir)
            {
                var filepath = Path.Combine(targetDir, fsentry.Name);

                if (fsentry is ICloudDirectoryEntry)
                {
                    Console.WriteLine("Created: {0}", filepath);
                    Directory.CreateDirectory(filepath);
                    DownloadFolder(dropBoxStorage, fsentry as ICloudDirectoryEntry, filepath, sourceDir);
                }
                else
                {
                    dropBoxStorage.DownloadFile(remoteDir, fsentry.Name, targetDir, UploadDownloadProgress);
                }
            }
        }

        static void Main(string[] args)
        {
            CloudStorage dropBoxStorage = new CloudStorage();

            var dropBixConfig = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.DropBox);

            ICloudStorageAccessToken accessToken = null;

            using (FileStream fs = File.Open(@"C:\Users\Michael\token.txt", FileMode.Open, FileAccess.Read, FileShare.None))
            {
                accessToken = dropBoxStorage.DeserializeSecurityToken(fs);
            }

            var storageToken = dropBoxStorage.Open(dropBixConfig, accessToken);

            //do stuff
            //var root = dropBoxStorage.GetRoot();

            var publicFolder = dropBoxStorage.GetFolder("/Public");

            foreach (var folder in publicFolder)
            {
                Boolean bIsDirectory = folder is ICloudDirectoryEntry;

                Console.WriteLine("{0}: {1}", bIsDirectory ? "DIR" : "FIL", folder.Name);
            }

            string remoteDirName = @"/Public/IQSWS";
            string targetDir = @"C:\Users\Michael\";
            var remoteDir = dropBoxStorage.GetFolder(remoteDirName);

            DownloadFolder(dropBoxStorage, remoteDir, targetDir, remoteDirName);

            dropBoxStorage.Close();
        }

        public delegate void FileOperationProgressChanged(object sender, FileDataTransferEventArgs e);    
    }

在循环找到 中的第一个文件后else,它会下载它,然后移动到下一个文件,但是它会在 上引发异常foreach

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Collection was modified; enumeration operation may not execute.
  Source=mscorlib
  StackTrace:
       at System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator.MoveNext()
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 29
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 39
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 39
       at StartServer.Program.DownloadFolder(CloudStorage dropBoxStorage, ICloudDirectoryEntry remoteDir, String targetDir, String sourceDir) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 39
       at StartServer.Program.Main(String[] args) in c:\Users\Michael\Documents\Visual Studio 2012\Projects\IQS Source\StartServer\StartServer\Program.cs:line 80
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

为什么会这样?当我所做的只是下载文件时,为什么要编辑数组?

4

2 回答 2

1

您将整个集合传递给remoteDirDownloadFile 方法,如下所示:

// AppLimit.CloudComputing.SharpBox.CloudStorage
public void DownloadFile(ICloudDirectoryEntry parent, string name, string targetPath, FileOperationProgressChanged delProgress)
{
    if (parent == null || name == null || targetPath == null)
    {
        throw new SharpBoxException(SharpBoxErrorCodes.ErrorInvalidParameters);
    }
    targetPath = Environment.ExpandEnvironmentVariables(targetPath);
    ICloudFileSystemEntry child = parent.GetChild(name);
    using (FileStream fileStream = new FileStream(Path.Combine(targetPath, name), FileMode.Create, FileAccess.Write, FileShare.None))
    {
        child.GetDataTransferAccessor().Transfer(fileStream, nTransferDirection.nDownload, delProgress, null);
    }
}

在这个方法中唯一parent可以修改的地方似乎是它调用GetChild. 查看 GetChild(我使用了 IlSpy):

public ICloudFileSystemEntry GetChild(string name)
{
  return this.GetChild(name, true);
}

public ICloudFileSystemEntry GetChild(string name, bool bThrowException)
{
  this.RefreshResource();
  ICloudFileSystemEntry cloudFileSystemEntry;
  this._subDirectories.TryGetValue(name, out cloudFileSystemEntry);
  if (cloudFileSystemEntry == null && bThrowException)
  {
    throw new SharpBoxException(SharpBoxErrorCodes.ErrorFileNotFound);
  }
  return cloudFileSystemEntry;
}

这反过来又调用RefreshResource了集合。看起来像这样(假设使用了 Dropbox 实现):

// AppLimit.CloudComputing.SharpBox.StorageProvider.BaseObjects.BaseDirectoryEntry
private void RefreshResource()
{
    this._service.RefreshResource(this._session, this);
    this._subDirectoriesRefreshedInitially = true;
}


// AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox.Logic.DropBoxStorageProviderService
public override void RefreshResource(IStorageProviderSession session, ICloudFileSystemEntry resource)
{
    string resourceUrlInternal = this.GetResourceUrlInternal(session, resource);
    int num;
    string text = DropBoxRequestParser.RequestResourceByUrl(resourceUrlInternal, this, session, out num);
    if (text.Length == 0)
    {
        throw new SharpBoxException(SharpBoxErrorCodes.ErrorCouldNotRetrieveDirectoryList);
    }
    DropBoxRequestParser.UpdateObjectFromJsonString(text, resource as BaseFileEntry, this, session);
}

现在,这然后调用UpdateObjectFromJsonString(我不会在这里粘贴,因为它很大),但这似乎更新了resource属于集合的对象。因此你的收藏被改变了......你的例外。

如果您对正在发生的事情感兴趣,我建议您将源下载到 SharpBox 或使用 IlSpy 反汇编二进制文件。但简而言之,如果您以这种方式下载文件,它将修改集合。

也许使用DownloadFile未在整个集合中传递的其他重载之一。

于 2013-10-08T14:19:48.800 回答
0

不确定问题是否已解决,但根据我的经验,修改的集合需要您将 IEnumerable 对象转换为 ToList() 以便它不会急于加载。

于 2014-10-21T11:41:03.863 回答