Compartir vía


Complemento de SharePoint de ejemplo para la carga de archivos de gran tamaño

El ejemplo Core.LargeFileUpload muestra cómo usar un complemento hospedado por el proveedor para cargar archivos grandes en SharePoint y cómo eludir el límite de 2 MB para la carga de archivos.

Use esta solución si desea cargar archivos de más de 2 MB en SharePoint.

Este ejemplo se ejecuta como una aplicación de consola que carga archivos de gran tamaño a una biblioteca de documentos usando uno de los métodos siguientes:

En la siguiente tabla se recogen los métodos de carga de archivos que están disponibles y se describe cuándo usar cada método.

Opciones para cargar archivos

Opción de carga de archivos Consideraciones ¿Cuándo se debe usar? Plataformas compatibles
La propiedad Content de la clase FileCreationInformation. El tamaño máximo de archivos que se pueden cargar es de 2 MB. El agotamiento del tiempo de espera ocurre después de 30 minutos. Use esta opción únicamente para cargar archivos de menos de 2 MB. SharePoint Server, SharePoint Online
Método de SaveBinaryDirect en la clase File. No tiene límites de tamaño de archivo. El agotamiento del tiempo de espera ocurre después de 30 minutos. Solo debe usar este método si está usando una directiva de autenticación de usuario. La directiva de autenticación de usuario no está disponible en un complemento de SharePoint, pero puede usarse en complementos de dispositivo nativo, Windows PowerShell y aplicaciones de consola de Windows. SharePoint Server, SharePoint Online
La propiedad ContentStream en la clase FileCreationInformation. No tiene límites de tamaño de archivo. El agotamiento del tiempo de espera ocurre después de 30 minutos. Recomendado para:
- SharePoint Server
- SharePoint Online cuando el archivo tiene menos de 10 MB.
SharePoint Server, SharePoint Online
Cargar un único archivo como un conjunto de paquetes mediante los métodos StartUpload, ContinueUpload y FinishUpload en la clase File. No tiene límites de tamaño de archivo. El agotamiento del tiempo de espera ocurre después de 30 minutos. Debe cargar cada fragmento del archivo dentro de los 30 minutos de finalización del fragmento anterior para evitar que se agote el tiempo de espera. Recomendado para SharePoint Online cuando el archivo tiene más de 10 MB. SharePoint Online

Antes de empezar

Para empezar, descargue el complemento de ejemplo Core.LargeFileUpload desde el proyecto Modelos y prácticas de desarrollo de Office 365 en GitHub.

Nota:

El código de este artículo se proporciona tal cual, sin garantía de ningún tipo, expresa o implícita, incluidas las garantías implícitas de aptitud para un propósito particular, comerciabilidad o ausencia de infracción.

Usar el complemento de ejemplo Core.LargeFileUpload

Al iniciar este código de ejemplo, aparece una aplicación de consola. Debe proporcionar una dirección URL de una colección de sitios de SharePoint Online y sus credenciales de inicio de sesión de Office 365.

Después de la autenticación, la aplicación de consola muestra una excepción. La excepción se produce cuando el método UploadDocumentContent de FileUploadService.cs intenta usar la propiedad FileCreationInformation.Content para cargar un archivo que tiene más de 2 MB. UploadDocumentContent también crea una biblioteca de documentos denominada Docs si no existe ya. La biblioteca de documentos Docs se usa más adelante en este ejemplo de código.

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

En FileUploadService.cs, este ejemplo de código proporciona tres opciones que puede usar para cargar archivos grandes en una biblioteca de documentos:

  • El método File.SaveBinaryDirect.
  • La propiedad FileCreationInformation.ContentStreamFileCreationInformation.ContentStream.
  • Los métodos StartUpload, ContinueUpload y FinishUpload en la clase File.

En FileUploadService.cs, SaveBinaryDirect usa el método Microsoft.SharePoint.Client.File.SaveBinaryDirect con un objeto FileStream para cargar archivos a una biblioteca de documentos.

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

En FileUploadService.cs, UploadDocumentContentStream usa la propiedad FileCreationInformation.ContentStream con un objeto FileStream para cargar un archivo a una biblioteca de documentos.

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

En FileUploadService.cs, UploadFileSlicePerSlice carga un archivo grande en una biblioteca de documentos como un conjunto de fragmentos o fragmentos. UploadFileSlicePerSlice realiza las siguientes tareas:

  1. Obtiene un nuevo GUID. Para cargar un archivo en fragmentos, debe usar un GUID único.
  2. Calcula el tamaño de bloque del fragmento en bytes. Para calcular el tamaño del bloque en bytes, UploadFileSlicePerSlice usa fileChunkSizeInMB, que especifica el tamaño de los fragmentos individuales en MB.
  3. Comprueba si el tamaño del archivo que quiere cargar (fileSize) es menor que o igual que el tamaño del fragmento (blockSize).
    • Si fileSize es menor o igual que el tamaño del fragmento, en el ejemplo se asegura que todavía se esté cargando el archivo usando la propiedad FileCreationInformation.ContentStream. Recuerde que el tamaño del fragmento recomendado es de 10 MB o superior.
    • Si fileSize es mayor que el tamaño del fragmento:
      • Se lee un fragmento del archivo en buffer.
      • Si el tamaño del fragmento es igual que el tamaño del archivo, se leyó el archivo completo. El fragmento se copia en lastBuffer. lastBuffer a continuación, usa File.FinishUpload para cargar el fragmento.
    • Si el tamaño del fragmento no es igual al tamaño del archivo, hay más de un fragmento del archivo para leer. Se llama a File.StartUpload para cargar el primer campo. fileoffset, que sirve como punto de partida del fragmento siguiente, se establece en la cantidad de bytes cargados desde el primer fragmento. Cuando se lee el fragmento siguiente, si no se ha alcanzado el último fragmento, se llama a File.ContinueUploadFile.ContinueUpload para cargar el siguiente fragmento del archivo. El proceso se repite hasta que se lea el último fragmento. Cuando se lee el último fragmento, File.FinishUpload carga el último fragmento y confirma el archivo. Después se cambia el contenido del archivo cuando finaliza este método.

Nota:

Tenga en cuenta las siguientes prácticas recomendadas:

  • Use un mecanismo de reintento en caso de que la carga se interrumpa. Cuando se interrumpe un archivo cargado, el archivo se denomina archivo sin terminar. Puede reiniciar la carga de un archivo sin terminar poco después de que la carga se interrumpiera. Los archivos sin terminar se quitan del servidor entre las 6 y las 24 después de que se interrumpiera el archivo sin terminar. Este período de eliminación puede cambiar sin previo aviso.
  • Al cargar un archivo en fragmentos en SharePoint Online, se coloca un bloqueo en el archivo en SharePoint Online. Cuando se produce una interrupción, el archivo permanece bloqueado durante 15 minutos. Si no se carga el siguiente fragmento del archivo a SharePoint Online en 15 minutos, se quita el bloqueo. Después de quitar el bloqueo, puede reanudar la carga u otro usuario puede comenzar a cargar el archivo. Si otro usuario inicia la carga del archivo, el archivo sin terminar se quitará de SharePoint Online. El período de tiempo que el bloqueo permanece en un archivo después de que se interrumpe una carga puede cambiar sin previo aviso.
  • Puede cambiar el tamaño del fragmento. Se recomienda usar un tamaño de fragmento de 10 MB.
  • Reanude un fragmento interrumpido mediante el seguimiento de qué fragmentos se cargaron correctamente.

Los fragmentos se deben cargar en orden secuencial. No se pueden cargar segmentos simultáneamente (por ejemplo, mediante un enfoque multiproceso).

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

Una vez finalizado el código de ejemplo, en el sitio de Office 365 puede ir a la biblioteca de documentos Docs si elige Recientes>Documentos. Compruebe que la biblioteca de documentos Docs contiene tres archivos grandes.

Consulte también