Поделиться через


Пример надстройки SharePoint для отправки больших файлов

В примере Core.LargeFileUpload показано, как использовать надстройку, размещенную у поставщика, для отправки больших файлов в SharePoint и как обойти ограничение на размер отправляемых файлов в 2 МБ.

Используйте это решение для отправки файлов, размер которых превышает 2 МБ, в SharePoint.

В этом примере используется консольное приложение, которое отправляет большие файлы в библиотеку документов с помощью одного из следующих способов:

В приведенной ниже таблице перечислены доступные способы отправки файлов и описаны ситуации, в которых они применимы.

Варианты отправки файлов

Вариант отправки файлов Особенности Когда применяется Поддерживаемые платформы
Свойство Content класса FileCreationInformation. Максимальный размер отправляемого файла не должен превышать 2 МБ. Время ожидания истекает через 30 минут. Используйте только для отправки файлов, которые меньше 2 МБ. SharePoint Server, SharePoint Online
Метод SaveBinaryDirect класса Файл. Ограничения на размер файла отсутствуют. Время ожидания истекает через 30 минут. Используйте этот метод только в том случае, если вы используете политику проверки подлинности только для пользователей. Политика проверки подлинности только для пользователей недоступна в надстройке SharePoint, но может использоваться в собственных надстройках устройств, Windows PowerShell и консольных приложениях Windows. SharePoint Server, SharePoint Online
Свойство ContentStream класса FileCreationInformation. Ограничения на размер файла отсутствуют. Время ожидания истекает через 30 минут. Рекомендуется для следующих платформ:
- SharePoint Server;
- SharePoint Online, если файл меньше 10 МБ.
SharePoint Server, SharePoint Online
Отправьте отдельный файл в виде набора блоков с использованием методов StartUpload, ContinueUpload и FinishUpload класса File. Ограничения на размер файла отсутствуют. Время ожидания истекает через 30 минут. Чтобы не истекло время ожидания, каждый блок файла должен быть отправлен в течение 30 минут с момента завершения отправки предыдущего блока. Рекомендуется для SharePoint Online, если файл больше 10 МБ. SharePoint Online

Подготовка

Чтобы приступить к работе, скачайте пример надстройки Core.LargeFileUpload из проекта Office 365 Developer Patterns and Practices (Шаблоны и методики разработки для Office 365) на портале GitHub.

Примечание.

Код, приведенный в этой статье, предоставляется "как есть" без какой-либо явной или подразумеваемой гарантии, включая подразумеваемые гарантии пригодности для какой-либо цели, для продажи или гарантии отсутствия нарушения прав иных правообладателей.

Использование примера надстройки Core.LargeFileUpload

При запуске этого примера кода появляется консольное приложение. Необходимо указать URL-адрес семейства веб-сайтов SharePoint Online и учетные данные для входа в Office 365.

После проверки подлинности в консольном приложении появляется сообщение об исключении. Исключение возникает, когда метод UploadDocumentContent в файле FileUploadService.cs пытается использовать свойство FileCreationInformation.Content для отправки файла, размер которого превышает 2 МБ. UploadDocumentContent также создает библиотеку документов с именем Документы, если она еще не существует. Библиотека документов Документы позже будет использоваться в этом примере кода.

public void UploadDocumentContent(ClientContext ctx, string libraryName, string filePath)
{
  Web web = ctx.Web;

  // Ensure that target library exists. Create if it is missing.
  if (!LibraryExists(ctx, web, libraryName))
  {
    CreateLibrary(ctx, web, libraryName);
  }

  FileCreationInformation newFile = new FileCreationInformation();

  // The next line of code causes an exception to be thrown for files larger than 2 MB.
  newFile.Content = System.IO.File.ReadAllBytes(filePath);
  newFile.Url = System.IO.Path.GetFileName(filePath);

  // Get instances to the given library.
  List docs = web.Lists.GetByTitle(libraryName);

  // Add file to the library.
  Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(newFile);
  ctx.Load(uploadFile);
  ctx.ExecuteQuery();
}

Этот пример кода в файле FileUploadService.cs содержит три варианта, которые можно использовать для отправки больших файлов в библиотеку документов:

  • Метод File.SaveBinaryDirect.
  • Свойство FileCreationInformation.ContentStream.
  • Методы StartUpload, ContinueUpload и FinishUpload класса File.

В FileUploadService.csSaveBinaryDirect использует метод Microsoft.SharePoint.Client.File.SaveBinaryDirect с объектом FileStream для отправки файлов в библиотеку документов.

public void SaveBinaryDirect(ClientContext ctx, string libraryName, string filePath)
{
  Web web = ctx.Web;
  // Ensure that the target library exists. Create it if it is missing.
  if (!LibraryExists(ctx, web, libraryName))
  {
    CreateLibrary(ctx, web, libraryName);
  }

  using (FileStream fs = new FileStream(filePath, FileMode.Open))
  {
    Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, string.Format("/{0}/{1}", libraryName, System.IO.Path.GetFileName(filePath)), fs, true);
  }
}

В FileUploadService.csUploadDocumentContentStream использует свойство FileCreationInformation.ContentStream с объектом FileStream для отправки файлов в библиотеку документов.

public void UploadDocumentContentStream(ClientContext ctx, string libraryName, string filePath)
{
  Web web = ctx.Web;
  // Ensure that the target library exists. Create it if it is missing.
  if (!LibraryExists(ctx, web, libraryName))
  {
    CreateLibrary(ctx, web, libraryName);
  }

  using (FileStream fs = new FileStream(filePath, FileMode.Open))
  {
    FileCreationInformation flciNewFile = new FileCreationInformation();

    // This is the key difference for the first case - using ContentStream property
    flciNewFile.ContentStream = fs;
    flciNewFile.Url = System.IO.Path.GetFileName(filePath);
    flciNewFile.Overwrite = true;

    List docs = web.Lists.GetByTitle(libraryName);
    Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(flciNewFile);

    ctx.Load(uploadFile);
    ctx.ExecuteQuery();
  }
}

В FileUploadService.csUploadFileSlicePerSlice отправляет большой файл в библиотеку документов как набор блоков или фрагментов. UploadFileSlicePerSlice выполняет следующие задачи:

  1. Получает новый идентификатор GUID. Чтобы отправить файл в виде блоков, необходимо использовать уникальный GUID.
  2. Вычисляет размер блока в байтах. Чтобы вычислить размер блока в байтах, метод UploadFileSlicePerSlice использует fileChunkSizeInMB, который указывает размер отдельных блоков в МБ.
  3. Проверяет, не является ли размер файла для отправки (fileSize) меньшим или равным размеру блока (blockSize).
    • Если fileSize меньше или равен размеру блока, то пример обеспечивает отправку файла, используя свойство FileCreationInformation.ContentStream. Помните, что рекомендуется использовать блоки размером 10 МБ или больше.
    • Если fileSize больше размера блока:
      • Блок файла считывается в buffer.
      • Если размер блока равен размеру файла, считывается весь файл. Блок копируется в lastBuffer. lastBuffer затем использует File.FinishUpload для отправки блока.
    • Если размер блока не равен размеру файла, необходимо считать несколько блоков из файла. Вызывается File.StartUpload для отправки первого блока. Для fileoffset, которая используется в качестве начальной позиции следующего блока, задается количество байтов, отправленных из первого блока. При считывании следующего блока, если не достигнут последний блок, вызывается File.ContinueUpload для отправки следующего блока файла. Процесс повторяется до тех пор, пока не будет считан последний блок. После считывания последнего блока метод File.FinishUpload отправляет его и фиксирует файл. После завершения работы этого метода содержимое файла изменяется.

Примечание.

Обратите внимание на следующие рекомендации:

  • Используйте механизм повтора на случай, если отправка будет прервана. Если отправка файла прерывается, такой файл называется незавершенным. Вы можете перезапустить отправку незавершенного файла вскоре после того, как она была прервана. Незавершенное файлы удаляются с сервера через период от 6 до 24 часов после прерывания отправки. Этот период удаления может измениться без уведомления.
  • При отправке файла в SharePoint Online в виде блоков он блокируется в SharePoint Online. Если отправка прерывается, файл остается заблокированным в течение 15 минут. Если следующий блок файла не отправляется в SharePoint Online в течение 15 минут, то блокировка удаляется. После удаления блокировки вы можете возобновить отправку или другой пользователь может начать отправку файла. Если другой пользователь начинает отправку файла, незавершенный файл удаляется из SharePoint Online. Период блокировки файла после прерывания отправки может измениться без уведомления.
  • Вы можете изменить размер блока. Рекомендуется использовать блоки размером 10 МБ.
  • Чтобы возобновить прерванную отправку, отслеживайте успешно отправленные блоки.

Блоки должны отправляться последовательно. Одновременная отправка нескольких секторов (например, с помощью многопоточного подхода) невозможна.

public Microsoft.SharePoint.Client.File UploadFileSlicePerSlice(ClientContext ctx, string libraryName, string fileName, int fileChunkSizeInMB = 3)
{
  // Each sliced upload requires a unique ID.
  Guid uploadId = Guid.NewGuid();

  // Get the name of the file.
  string uniqueFileName = Path.GetFileName(fileName);

  // Ensure that target library exists, and create it if it is missing.
  if (!LibraryExists(ctx, ctx.Web, libraryName))
  {
    CreateLibrary(ctx, ctx.Web, libraryName);
  }
  // Get the folder to upload into.
  List docs = ctx.Web.Lists.GetByTitle(libraryName);
  ctx.Load(docs, l => l.RootFolder);
  // Get the information about the folder that will hold the file.
  ctx.Load(docs.RootFolder, f => f.ServerRelativeUrl);
  ctx.ExecuteQuery();

  // File object.
  Microsoft.SharePoint.Client.File uploadFile = null;

  // Calculate block size in bytes.
  int blockSize = fileChunkSizeInMB * 1024 * 1024;

  // Get the information about the folder that will hold the file.
  ctx.Load(docs.RootFolder, f => f.ServerRelativeUrl);
  ctx.ExecuteQuery();


  // Get the size of the file.
  long fileSize = new FileInfo(fileName).Length;

  if (fileSize <= blockSize)
  {
    // Use regular approach.
    using (FileStream fs = new FileStream(fileName, FileMode.Open))
    {
      FileCreationInformation fileInfo = new FileCreationInformation();
      fileInfo.ContentStream = fs;
      fileInfo.Url = uniqueFileName;
      fileInfo.Overwrite = true;
      uploadFile = docs.RootFolder.Files.Add(fileInfo);
      ctx.Load(uploadFile);
      ctx.ExecuteQuery();
      // Return the file object for the uploaded file.
      return uploadFile;
    }
  }
  else
  {
    // Use large file upload approach.
    ClientResult<long> bytesUploaded = null;

    FileStream fs = null;
    try
    {
      fs = System.IO.File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
      using (BinaryReader br = new BinaryReader(fs))
      {
        byte[] buffer = new byte[blockSize];
        Byte[] lastBuffer = null;
        long fileoffset = 0;
        long totalBytesRead = 0;
        int bytesRead;
        bool first = true;
        bool last = false;

        // Read data from file system in blocks.
        while ((bytesRead = br.Read(buffer, 0, buffer.Length)) > 0)
        {
          totalBytesRead = totalBytesRead + bytesRead;

          // You've reached the end of the file.
          if (totalBytesRead == fileSize)
          {
            last = true;
            // Copy to a new buffer that has the correct size.
            lastBuffer = new byte[bytesRead];
            Array.Copy(buffer, 0, lastBuffer, 0, bytesRead);
          }

          if (first)
          {
            using (MemoryStream contentStream = new MemoryStream())
            {
              // Add an empty file.
              FileCreationInformation fileInfo = new FileCreationInformation();
              fileInfo.ContentStream = contentStream;
              fileInfo.Url = uniqueFileName;
              fileInfo.Overwrite = true;
              uploadFile = docs.RootFolder.Files.Add(fileInfo);

              // Start upload by uploading the first slice.
              using (MemoryStream s = new MemoryStream(buffer))
              {
                // Call the start upload method on the first slice.
                bytesUploaded = uploadFile.StartUpload(uploadId, s);
                ctx.ExecuteQuery();
                // fileoffset is the pointer where the next slice will be added.
                fileoffset = bytesUploaded.Value;
              }

              // You can only start the upload once.
              first = false;
            }
          }
          else
          {
            if (last)
            {
              // Is this the last slice of data?
              using (MemoryStream s = new MemoryStream(lastBuffer))
              {
                // End sliced upload by calling FinishUpload.
                uploadFile = uploadFile.FinishUpload(uploadId, fileoffset, s);
                ctx.ExecuteQuery();

                // Return the file object for the uploaded file.
                return uploadFile;
              }
            }
            else
            {
              using (MemoryStream s = new MemoryStream(buffer))
              {
                // Continue sliced upload.
                bytesUploaded = uploadFile.ContinueUpload(uploadId, fileoffset, s);
                ctx.ExecuteQuery();
                // Update fileoffset for the next slice.
                fileoffset = bytesUploaded.Value;
              }
            }
          }
        } // while ((bytesRead = br.Read(buffer, 0, buffer.Length)) > 0)
      }
    }
    finally
    {
      if (fs != null)
      {
        fs.Dispose();
      }
    }
  }

  return null;
}

После завершения работы примера кода на сайте Office 365 можно перейти к библиотеке документов Документы, выбрав пункты Последние>Документы. Убедитесь, что библиотека документов Документы содержит три больших файла.

См. также