上传到 Dropbox 时出错

Getting an error when uploading to Dropbox

我正在尝试将文件上传到保管箱。

这是我到目前为止所说的:

    using (var stream = new MemoryStream(File.ReadAllBytes(fileName)))
    {
      var numChunks = (int) Math.Ceiling((double) stream.Length / chunkSize);
      var buffer = new byte[chunkSize];
      string sessionId = null;

      if (numChunks == 1)
      {
        using (var memStream = new MemoryStream(buffer, 0, chunkSize))
        {
          Console.WriteLine($"Sending file: {path}");
          var tst = await client.Files.UploadAsync(path, WriteMode.Overwrite.Instance, body: memStream);
        }
      }
      else
      {
        for (var idx = 0; idx < numChunks; idx++)
        {
          Console.WriteLine($"Uploading chunk {idx + 1} / {numChunks}.");
          var byteRead = stream.Read(buffer, 0, chunkSize);

          using (var memStream = new MemoryStream(buffer, 0, byteRead))
          {
            if (idx == 0)
            {
              var result = await client.Files.UploadSessionStartAsync(body: memStream);
              sessionId = result.SessionId;
            }

            var cursor = new UploadSessionCursor(sessionId, (ulong) (chunkSize * idx));

            if (idx == numChunks - 1)
            {
              Console.WriteLine($"Finalizing file: {path}");
              var response = await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(path), memStream);
            }
            else
            {
              await client.Files.UploadSessionAppendV2Async(cursor, body: memStream);
            }
          }
        }
      }

      var url = string.Empty;
      var link = await client.Sharing.ListSharedLinksAsync(path);

      if (link.Links.Count == 0)
      {
        var result = await client.Sharing.CreateSharedLinkWithSettingsAsync(path);
        url = result.Url;
      }
      else
      {
        url = link.Links[0].Url;
      }

      Console.WriteLine();
      Console.WriteLine("Dropbox Download Link:");
      Console.WriteLine(url);
      Console.WriteLine();
      //Console.ReadKey();
    }

当我尝试发送一个大文件时,我收到这条消息:

我正在计算大小文件。如果文件大于 chunksize。我无法让它发送文件,我只是收到一个错误。

发生在这一行:

var response = await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(path), memStream);

有什么建议吗?

对于第一个块 idx==0,您只需调用 UploadSessionStartAsync,您还可以调用 UploadSessionAppendV2Async。试试这个:

...
using (var memStream = new MemoryStream(buffer, 0, byteRead))
{
    if (idx == 0)
    {
        var result = await client.Files.UploadSessionStartAsync(body: memStream);
          sessionId = result.SessionId;
    }
    else
    {
        var cursor = new UploadSessionCursor(sessionId, (ulong) (chunkSize * idx));

        if (idx == numChunks - 1)
        {
          Console.WriteLine($"Finalizing file: {path}");
          var response = await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(path), memStream);
        }
        else
        {
          await client.Files.UploadSessionAppendV2Async(cursor, body: memStream);
        }
    }
}
...

不是 运行 在本地,也没有使用 Dropbox 的客户端,但我看到以下...

  1. 可能,虽然手动调试速度较慢,但​​您可能会错过问题。
  2. 预计该错误消息 轻微 具有误导性。总的来说,是对的。但是当您的原始流被更改.
  3. 时,应该进行额外的检查以发现这种情况
  4. 让我添加更多关于 'what the hell is happening here?!.' 的 sync/async 混沌数据。首先,您的 for 运行 同步 - 所有上传会话在短时间内并行开始。 第二,每个 for 都有自己的 block-level scope,在同步上下文中有 using (...) {...} 语法糖。 所有 var memStream s 在上层同步上下文中相互覆盖。然后,每个线程在它自己的异步上下文中完成它的工作。看看var response。它是一个循环变量,并且未在您的主 SYNC 上下文中使用。 它没有在 using 闭包之外声明。 所以这一行在同步上下文中是不可等待的。在这种情况下,using 将在 memStream 被消耗时完成,但 UploadSessionFinishAsync 将继续工作。
  5. 为什么它只发生在 var response = await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(path), memStream);?想一想,这可能是每个 await client.Files... 调用中的问题,但只有 client.Files.UploadSessionFinishAsync 尝试对传递的 memStream 执行某些操作。例如,将其关闭作为最后一步。或处理 memStream,放弃流,做另一项工作,例如向 Dropbox 请求以获得最终上传结果。
  6. 关于修复的想法。我认为您需要在 for 范围之上声明最终结果 var response。然后只需在最后一个块处理时设置结果。在这种情况下 using 将不得不等待它的结果,然后它才能处置 memStream。就像 sessionId = result.SessionId; 一样。或者只是在 using 结束之前明确等待其结果。
  7. 代码优化。对于短文件,您不需要 buffersessionId。它们用于多个上传线程。对于大文件 - return UploadSessionFinishAsync 来自循环的结果。也许,将多个 memStream 声明为不同的变量。不确定 UploadSessionAppendV2Async 结果。如果是 void 就可以了。否则,这样的结果也需要等待。可能是这样的:
//outer vars
SomeDropboxFileUploadResultOrElse uploadResult;
string sessionId = null;

//original full file read
using (var stream = new MemoryStream(File.ReadAllBytes(fileName)))
{
   var numChunks = (int) Math.Ceiling((double) stream.Length / chunkSize);
   if (numChunks == 1)
   {
       Console.WriteLine($"Sending file: {path}");
       uploadResult = await client.Files.UploadAsync(path, WriteMode.Overwrite.Instance, body: stream);
   }
   else
   {
       var buffer = new byte[chunkSize];
       for (var idx = 0; idx < numChunks; idx++)
       {
           Console.WriteLine($"Uploading chunk {idx + 1} / {numChunks}.");
           var byteRead = stream.Read(buffer, 0, chunkSize);

           using (var memStream = new MemoryStream(buffer, 0, byteRead))
           {
               if (idx == 0)
               {
                   var result = await client.Files.UploadSessionStartAsync(body: memStream);
                   sessionId = result.SessionId;
               }
               //prevent 2+ parts processing on idx == 0 iteration, start thread in the sync scope but wait for sessionId value in the async thread
               else
               {
                   var cursor = new UploadSessionCursor(sessionId, (ulong)(chunkSize * idx));
                   if (idx == numChunks - 1)
                   {
                       Console.WriteLine($"Finalizing file: {path}");
                       //explicitly pass result to outer scope, then the execution could be continued, memStream could be closed below
                       uploadResult = await client.Files.UploadSessionFinishAsync(cursor, new CommitInfo(path), memStream);
                   }
                   else
                   {
                       await client.Files.UploadSessionAppendV2Async(cursor, body: memStream);
                   }
               }
           } //memStream?.Dispose(); 
       }
   }
...
}

希望这会有所帮助。