java google drive api V3 MultiPart & Resumable Upload - PullRequest
1 голос
/ 30 мая 2020

Мне нужна помощь в написании многокомпонентной и возобновляемой загрузки больших файлов (> 5 МБ). Пока мне удалось запустить только многопользовательскую загрузку, но я не знаю, как возобновить ее, когда пользователь приостанавливает ее или во время сети неудачи.

Под «Возобновлением» я имею в виду, что я не знаю, как

1) получить общее количество байтов, уже загруженных на диск

2) как использовать это значение в Заголовок Content-Range

3) как даже приостановить эту загрузку при взаимодействии с пользователем [executeAsInputStream() Может быть?]

Это то, что я делал до сих пор. Мне нужен код для возобновления с того места, где он прекратил загрузку, даже если бы я принудительно остановил приложение и перезапустил его

   Drive service = GDrive.getService(); //Drive Specific Initialization Copied From QuickStart But with DriveScopes.FILES

   File fileMetadata = new File();
   fileMetadata.setName("Video.mp4"); //Video File
   fileMetadata.setMimeType("application/vnd.google-apps.video");

   java.io.File filePath = new java.io.File("E:\\large-file-60MB.mp4");//Large File Of 60 Mega Bytes
   FileContent mediaContent = new FileContent("video/mp4",filePath);

   Drive.Files.Create create=service.files().create(fileMetadata,mediaContent);

   MediaHttpUploader uploader=create.getMediaHttpUploader();
   uploader.setDirectUploadEnabled(false);                       //Use Resumable MultiPart Upload Protocol
   uploader.setChunkSize(2*MediaHttpUploader.MINIMUM_CHUNK_SIZE); //Chunks Of Bytes To Upload With Each Request

  // HttpHeaders headers=new HttpHeaders();
  // headers.put("Content-Range",?);          //This is not actual code which I used here but after reading the drive docs they talk about this header and I am not sure how or when to use it
  // uploader.setInitiationHeaders(headers);

   uploader.setProgressListener((uploading)->
   {
    switch (uploading.getUploadState())
    {
      case INITIATION_STARTED:System.out.println("Initiation has started!");
      break;
      case INITIATION_COMPLETE:System.out.println("Initiation is complete!");
      break;
      case MEDIA_IN_PROGRESS:
      System.out.println("Progress="+uploading.getProgress());
      System.out.println("Bytes="+uploading.getNumBytesUploaded());
      break;
      case MEDIA_COMPLETE:System.out.println("Upload is complete!");
    }
   });

   create.execute(); 

1 Ответ

1 голос
/ 02 июня 2020

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

  • Как получить общее количество байтов, уже загруженных на диск
  • Как использовать значение в заголовке Content-Range
  • Как приостановить возобновляемую загрузку

Из документации Google на Прямая и возобновляемая загрузка носителей на Java Документация клиентской библиотеки API:

Детали реализации

Основные интересующие классы: MediaHttpUploader и MediaHttpProgressListener .

Если методы в сгенерированных c библиотеках, специфичных для службы, содержат параметр mediaUpload в документе Discovery для этих методов создается удобный метод, который принимает InputStreamContent в качестве параметра. * 10 30 *

Например, метод insert Drive API поддерживает mediaUpload, и вы можете использовать следующий код для загрузки файла:

class CustomProgressListener implements MediaHttpUploaderProgressListener {
  public void progressChanged(MediaHttpUploader uploader) throws IOException {
    switch (uploader.getUploadState()) {
      case INITIATION_STARTED:
        System.out.println("Initiation has started!");
        break;
      case INITIATION_COMPLETE:
        System.out.println("Initiation is complete!");
        break;
      case MEDIA_IN_PROGRESS:
        System.out.println(uploader.getProgress());
        break;
      case MEDIA_COMPLETE:
        System.out.println("Upload is complete!");
    }
  }
}

File mediaFile = new File("/tmp/driveFile.jpg");
InputStreamContent mediaContent =
    new InputStreamContent("image/jpeg",
        new BufferedInputStream(new FileInputStream(mediaFile)));
mediaContent.setLength(mediaFile.length());

Drive.Files.Insert request = drive.files().insert(fileMetadata, mediaContent);
request.getMediaHttpUploader().setProgressListener(new CustomProgressListener());
request.execute();

Однако эти классы абстрактны удалите такие вещи, как URI местоположения, который возвращается при создании возобновляемой загрузки, поэтому, если вы хотите иметь возможность это сделать, вам нужно будет выполнить шаги инициации возобновляемой загрузки, как описано здесь . Однако все это делается вручную, а не напрямую с использованием клиентской библиотеки Google Drive API.

Чтобы ответить на первый вопрос, вам решать, как вы сохраните, сколько байтов было загружено. Вместо того, чтобы думать «сколько уже на диске» , подумайте «сколько я уже загрузил?» .

Вы можете сохранить это как переменную локально, если хотите, так как он будет кратен размеру вашего блока (2 * MediaHttpUploader.MINIMUM_CHUNK_SIZE в вашем случае) и его будет легко отслеживать.

Дело в том, что на самом деле это не нужно. Вы можете просто использовать подстановочный знак, чтобы указать, что текущая позиция вашего файла неизвестна в соответствии с документацией (выделено мной):

Если запрос на загрузку завершается до ответа, или если вы получите ответ 503 Service Unavailable, затем вам необходимо возобновить прерванную загрузку.

Чтобы запросить статус загрузки, создайте пустой запрос PUT к URI возобновляемого сеанса.

Добавьте заголовок Content-Range, чтобы указать, что текущая позиция в файле неизвестна. Например, установите Content-Range на */2000000, если общая длина файла составляет 2 000 000 байт. Если вы не знаете полный размер файла, установите Content-Range на */*.

Если вы хотите отслеживать байты, вы можете указать его в заголовке Content-Range как

Content-Range: bytes_so_far/total_bytes

Шаги:

Для инициализации возобновляемой загрузки, вам необходимо сделать запрос POST к конечной точке /upload Drive API. Вам не нужно использовать для этого клиентскую библиотеку Drive API (и на самом деле, если вы хотите получить URI возобновляемого сеанса, вы не можете этого сделать, поскольку клиентская библиотека не дает вам этого).

Предполагая, что вы иметь определение ваших учетных данных из:

GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(...);

Затем сделайте запрос POST, содержащий метаданные файла:

URL requestUrl = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");

String requestBody = "{\"name\": \"fileName\"}";

HttpURLConnection request = (HttpURLConnection) requestUrl.openConnection();

request.setRequestMethod("POST");
request.setDoInput(true);
request.setDoOutput(true);
request.setRequestProperty("Authorization", "Bearer " + credential.getToken());
request.setRequestProperty("X-Upload-Content-Type", "file/mimetype");
request.setRequestProperty("X-Upload-Content-Length", number_of_bytes_of_your_file);
request.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", requestBody.getBytes().length));

OutputStream outputStream = request.getOutputStream();
outputStream.write(requestBody.getBytes());
outputStream.close();

request.connect();

URI сеанса - куда позвонить, чтобы возобновить, если вам нужно - возвращается в заголовках ответа от API. После подключения вы можете получить этот URI из ответа:

if (request.getResponseCode() == HttpURLConnection.HTTP_OK) {
    URL sessionUri = new URL(request.getHeaderField("location"));
}

Теперь у вас есть URI сеанса - с его помощью вы можете загружать фрагменты файла на Диск по своему усмотрению. Теперь вам нужно использовать этот URI в качестве точки загрузки для последующих загрузок.

Однако помните: URI возобновляемого сеанса истекает через неделю.

Как приостановить возобновляемую загрузку:

Это на самом деле все зависит от того, как вы sh это реализовать. Например, вы можете выделить al oop или иметь гигантскую кнопку PAUSE THIS UPLOAD в GUI, которая переключает, будет ли продолжаться следующий раздел загрузки или нет.

Следует помнить, что при загрузке содержимое файла, запрос должен быть выполнен с использованием HTTP PUT, а не POST. Следуя предыдущему разделу:

// set these variables:
long beginningOfChunk = 0;
long chunkSize = 2 * MediaHttpUploader.MINIMUM_CHUNK_SIZE;
int chunksUploaded = 0;

// Here starts the upload chunk code:
HttpURLConnection request = (HttpURLConnection) sessionUri.openConnection();

request.setRequestMethod("PUT");
request.setDoOutput(true);
// change your timeout as you desire here:
request.setConnectTimeout(30000); 
request.setRequestProperty("Content-Type", "file/mimetype");

long bytesUploadedSoFar = chunksUploaded * chunkSize;

if (beginningOfChunk + chunkSize > number_of_bytes_of_your_file) {
    chunkSize = (int) number_of_bytes_of_your_file - beginningOfChunk;
}

request.setRequestProperty("Content-Length", String.format(Locale.ENGLISH, "%d", chunkSize));
request.setRequestProperty("Content-Range", "bytes " + beginningOfChunk + "-" + (beginningOfChunk + chunkSize - 1) + "/" + number_of_bytes_of_your_file);

byte[] buffer = new byte[(int) chunksize];
FileInputStream fileInputStream = new FileInputStream(yourFile);
fileInputStream.getChannel().position(beginningOfChunk);
fileInputStream.close();

OutputStream outputStream = request.getOutputStream();
outputStream.write(buffer);
outputStream.close();
request.connect();

chunksUploaded += 1;

// End of upload chunk section

Затем вы можете вызвать код фрагмента загрузки при повторении; в al oop, как функция; как хочешь. Поскольку это отдельный блок кода, вы можете называть его как хотите и, следовательно, реализовать какой-либо способ приостановки загрузки (через перерывы, засыпание, ожидание и т. Д. c).

Просто помните: вам понадобится чтобы сохранить URI сеанса для возобновления.


Обновление:

Похоже, что использование Drive V3 API напрямую для возобновляемых загрузок пока невозможно. Документация Java клиентской библиотеки ссылается на это при обсуждении того, когда использовать Drive: create по сравнению с c библиотеками, не предназначенными для обслуживания:

... метод вставки API Drive поддерживает mediaUpload, и вы можете использовать следующий код для загрузки файла:

code block

Вы также можете использовать функцию возобновляемой загрузки мультимедиа без специфичных для службы c сгенерированных библиотек.

Запрос функции:

Однако вы можете сообщить Google, что это функция, которая важна непосредственно для Drive API, а не требование использовать не-служебную спецификацию c библиотека. Google Issue Tracker - это место, где разработчики могут сообщать о проблемах и делать запросы функций для своих служб разработки. Страница для подачи запроса функции для Drive API: здесь .

Примечание о несоответствии: то, что называлось Drive.Files.Insert в Drive API V2, было изменено на Drive.Files.Create в Drive API V3.

Я знаю, что в целом это плохие новости, но надеюсь, что это будет полезно для вас!

Ссылки:

Вопросы по теме:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...