2013-10-08 2 views
1

그래서 재귀 적으로 디렉토리를 만들고 폴더의 파일을 전체적으로 다운로드하는 코드가 있습니다. 루프는 else의 첫 번째 파일을 발견 한 후 그러나 그것은 foreach에 예외를 발생, 그것을 다운로드하고 다음 파일로 이동sharpbox를 사용하여 파일 다운로드

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);  
    } 

: 여기서

코드이다

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: 

왜 이런 일이 발생합니까? 파일을 다운로드 할 때 배열이 편집되는 이유는 무엇입니까?

답변

1

이처럼 보이는 DownloadFile 방법으로 전체 컬렉션을 remoteDir 전달되고 있습니다

// 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를 호출하는 곳이 될 것으로 보인다. (나는 IlSpy을 사용) GetChild에서 상대 :

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를 호출합니다. 어떤이 같은 (드롭 박스 구현을 가정 한) 모습이 다음 (나는 그것이 거대한 때문에 여기에 붙여 않을거야) UpdateObjectFromJsonString를 호출, 지금

// 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); 
} 

을하지만,이 다음 resource 개체를 업데이트 할 보인다 컬렉션에 속합니다. 따라서 귀하의 컬렉션이 변경됩니다 ... 귀하의 예외.

SharpBox에 소스를 다운로드하거나 정확한 일에 관심이있는 경우 IlSpy를 사용하여 바이너리를 분해하는 것이 좋습니다. 간단히 말해서,이 방법으로 파일을 다운로드하면 컬렉션을 수정하게됩니다.

아마도 전체 컬렉션을 통과하지 않는 다른 DownloadFile 오버로드 중 하나를 사용할 수 있습니다.

0

문제가 해결되었거나 아니지만 내 경험에 따라 수정 된 컬렉션을 사용하면 IEnumerable 개체를 ToList()로 캐스팅해야 열심히로드되지 않습니다.