Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to overwrite for download to file #6994

Merged
merged 5 commits into from
Jan 2, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
Expand Down Expand Up @@ -680,8 +683,42 @@ private Mono<ReliableDownload> downloadHelper(BlobRange range, DownloadRetryOpti
* @return A reactive response containing the blob properties and metadata.
*/
public Mono<BlobProperties> downloadToFile(String filePath) {
return downloadToFile(filePath, false);
}

/**
* Downloads the entire blob into a file specified by the path.
*
* <p>If overwrite is set to false, the file will be created and must not exist, if the file already exists a
* {@link FileAlreadyExistsException} will be thrown.</p>
*
* <p>Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link
* AppendBlobClient}.</p>
*
* <p><strong>Code Samples</strong></p>
*
* {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String-boolean}
*
* <p>For more information, see the
* <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob">Azure Docs</a></p>
*
* @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written.
* @param overwrite Whether or not to overwrite the file, should the file exist.
* @return A reactive response containing the blob properties and metadata.
*/
public Mono<BlobProperties> downloadToFile(String filePath, boolean overwrite) {
try {
return downloadToFileWithResponse(filePath, null, null, null, null, false).flatMap(FluxUtil::toMono);
Set<OpenOption> openOptions = null;
if (overwrite) {
openOptions = new HashSet<>();
openOptions.add(StandardOpenOption.CREATE);
openOptions.add(StandardOpenOption.TRUNCATE_EXISTING); // If the file already exists and it is opened
// for WRITE access, then its length is truncated to 0.
openOptions.add(StandardOpenOption.READ);
openOptions.add(StandardOpenOption.WRITE);
}
return downloadToFileWithResponse(filePath, null, null, null, null, false, openOptions)
.flatMap(FluxUtil::toMono);
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
Expand Down Expand Up @@ -720,34 +757,81 @@ public Mono<BlobProperties> downloadToFile(String filePath) {
public Mono<Response<BlobProperties>> downloadToFileWithResponse(String filePath, BlobRange range,
ParallelTransferOptions parallelTransferOptions, DownloadRetryOptions options,
BlobRequestConditions requestConditions, boolean rangeGetContentMd5) {
return downloadToFileWithResponse(filePath, range, parallelTransferOptions, options, requestConditions,
rangeGetContentMd5, null);
}

/**
* Downloads the entire blob into a file specified by the path.
*
* <p>By default the file will be created and must not exist, if the file already exists a
* {@link FileAlreadyExistsException} will be thrown. To override this behavior, provide appropriate
* {@link OpenOption OpenOptions} </p>
*
* <p>Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link
* AppendBlobClient}.</p>
*
* <p>This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra
* call, provide the {@link BlobRange} parameter.</p>
*
* <p><strong>Code Samples</strong></p>
*
* {@codesnippet com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Set}
*
* <p>For more information, see the
* <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob">Azure Docs</a></p>
*
* @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written.
* @param range {@link BlobRange}
* @param parallelTransferOptions {@link ParallelTransferOptions} to use to download to file. Number of parallel
* transfers parameter is ignored.
* @param options {@link DownloadRetryOptions}
* @param requestConditions {@link BlobRequestConditions}
* @param rangeGetContentMd5 Whether the contentMD5 for the specified blob range should be returned.
* @param openOptions {@link OpenOption OpenOptions} to use to configure how to open or create the file.
* @return A reactive response containing the blob properties and metadata.
* @throws IllegalArgumentException If {@code blockSize} is less than 0 or greater than 100MB.
* @throws UncheckedIOException If an I/O error occurs.
*/
public Mono<Response<BlobProperties>> downloadToFileWithResponse(String filePath, BlobRange range,
ParallelTransferOptions parallelTransferOptions, DownloadRetryOptions options,
BlobRequestConditions requestConditions, boolean rangeGetContentMd5, Set<OpenOption> openOptions) {
try {
return withContext(context -> downloadToFileWithResponse(filePath, range, parallelTransferOptions, options,
requestConditions, rangeGetContentMd5, context));
requestConditions, rangeGetContentMd5, openOptions, context));
} catch (RuntimeException ex) {
return monoError(logger, ex);
}
}

Mono<Response<BlobProperties>> downloadToFileWithResponse(String filePath, BlobRange range,
ParallelTransferOptions parallelTransferOptions, DownloadRetryOptions downloadRetryOptions,
BlobRequestConditions requestConditions, boolean rangeGetContentMd5, Context context) {
BlobRequestConditions requestConditions, boolean rangeGetContentMd5, Set<OpenOption> openOptions,
Context context) {
BlobRange finalRange = range == null ? new BlobRange(0) : range;
final ParallelTransferOptions finalParallelTransferOptions =
ModelHelper.populateAndApplyDefaults(parallelTransferOptions);
BlobRequestConditions finalConditions = requestConditions == null
? new BlobRequestConditions() : requestConditions;

AsynchronousFileChannel channel = downloadToFileResourceSupplier(filePath);
// Default behavior is not to overwrite
if (openOptions == null) {
openOptions = new HashSet<>();
openOptions.add(StandardOpenOption.CREATE_NEW);
openOptions.add(StandardOpenOption.WRITE);
openOptions.add(StandardOpenOption.READ);
}

AsynchronousFileChannel channel = downloadToFileResourceSupplier(filePath, openOptions);
return Mono.just(channel)
.flatMap(c -> this.downloadToFileImpl(c, finalRange, finalParallelTransferOptions,
downloadRetryOptions, finalConditions, rangeGetContentMd5, context))
.doFinally(signalType -> this.downloadToFileCleanup(channel, filePath, signalType));
}

private AsynchronousFileChannel downloadToFileResourceSupplier(String filePath) {
private AsynchronousFileChannel downloadToFileResourceSupplier(String filePath, Set<OpenOption> openOptions) {
try {
return AsynchronousFileChannel.open(Paths.get(filePath), StandardOpenOption.READ, StandardOpenOption.WRITE,
StandardOpenOption.CREATE_NEW);
return AsynchronousFileChannel.open(Paths.get(filePath), openOptions, null);
} catch (IOException e) {
throw logger.logExceptionAsError(new UncheckedIOException(e));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import static com.azure.storage.common.implementation.StorageImplUtils.blockWithOptionalTimeout;

Expand Down Expand Up @@ -444,7 +448,42 @@ public BlobDownloadResponse downloadWithResponse(OutputStream stream, BlobRange
* @throws UncheckedIOException If an I/O error occurs
*/
public BlobProperties downloadToFile(String filePath) {
return downloadToFileWithResponse(filePath, null, null, null, null, false, null, Context.NONE).getValue();
return downloadToFile(filePath, false);
}

/**
* Downloads the entire blob into a file specified by the path.
*
* <p>If overwrite is set to false, the file will be created and must not exist, if the file already exists a
* {@link FileAlreadyExistsException} will be thrown.</p>
*
* <p>Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link
* AppendBlobClient}.</p>
*
* <p><strong>Code Samples</strong></p>
*
* {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String-boolean}
*
* <p>For more information, see the
* <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob">Azure Docs</a></p>
*
* @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written.
* @param overwrite Whether or not to overwrite the file, should the file exist.
* @return The blob properties and metadata.
* @throws UncheckedIOException If an I/O error occurs
*/
public BlobProperties downloadToFile(String filePath, boolean overwrite) {
Set<OpenOption> openOptions = null;
if (overwrite) {
openOptions = new HashSet<>();
openOptions.add(StandardOpenOption.CREATE);
openOptions.add(StandardOpenOption.TRUNCATE_EXISTING); // If the file already exists and it is opened
// for WRITE access, then its length is truncated to 0.
openOptions.add(StandardOpenOption.READ);
openOptions.add(StandardOpenOption.WRITE);
}
return downloadToFileWithResponse(filePath, null, null, null, null, false, openOptions, null, Context.NONE)
.getValue();
}

/**
Expand Down Expand Up @@ -481,8 +520,49 @@ public BlobProperties downloadToFile(String filePath) {
public Response<BlobProperties> downloadToFileWithResponse(String filePath, BlobRange range,
ParallelTransferOptions parallelTransferOptions, DownloadRetryOptions downloadRetryOptions,
BlobRequestConditions requestConditions, boolean rangeGetContentMd5, Duration timeout, Context context) {
return downloadToFileWithResponse(filePath, range, parallelTransferOptions, downloadRetryOptions,
requestConditions, rangeGetContentMd5, null, timeout, context);
}

/**
* Downloads the entire blob into a file specified by the path.
*
* <p>By default the file will be created and must not exist, if the file already exists a
* {@link FileAlreadyExistsException} will be thrown. To override this behavior, provide appropriate
* {@link OpenOption OpenOptions} </p>
*
* <p>Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link
* AppendBlobClient}.</p>
*
* <p>This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra
* call, provide the {@link BlobRange} parameter.</p>
*
* <p><strong>Code Samples</strong></p>
*
* {@codesnippet com.azure.storage.blob.specialized.BlobClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Set-Duration-Context}
*
* <p>For more information, see the
* <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob">Azure Docs</a></p>
*
* @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written.
* @param range {@link BlobRange}
* @param parallelTransferOptions {@link ParallelTransferOptions} to use to download to file. Number of parallel
* transfers parameter is ignored.
* @param downloadRetryOptions {@link DownloadRetryOptions}
* @param requestConditions {@link BlobRequestConditions}
* @param rangeGetContentMd5 Whether the contentMD5 for the specified blob range should be returned.
* @param openOptions {@link OpenOption OpenOptions} to use to configure how to open or create the file.
* @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised.
* @param context Additional context that is passed through the Http pipeline during the service call.
* @return A response containing the blob properties and metadata.
* @throws UncheckedIOException If an I/O error occurs.
*/
public Response<BlobProperties> downloadToFileWithResponse(String filePath, BlobRange range,
ParallelTransferOptions parallelTransferOptions, DownloadRetryOptions downloadRetryOptions,
BlobRequestConditions requestConditions, boolean rangeGetContentMd5, Set<OpenOption> openOptions,
Duration timeout, Context context) {
Mono<Response<BlobProperties>> download = client.downloadToFileWithResponse(filePath, range,
parallelTransferOptions, downloadRetryOptions, requestConditions, rangeGetContentMd5, context);
parallelTransferOptions, downloadRetryOptions, requestConditions, rangeGetContentMd5, openOptions, context);
return blockWithOptionalTimeout(download, timeout);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* Code snippets for {@link BlobAsyncClientBase}
Expand Down Expand Up @@ -130,14 +135,28 @@ public void downloadToFileCodeSnippet() {
client.downloadToFile(file).subscribe(response -> System.out.println("Completed download to file"));
// END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String

// BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean
// BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String-boolean
boolean overwrite = false; // Default value
client.downloadToFile(file, overwrite).subscribe(response -> System.out.println("Completed download to file"));
// END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFile#String-boolean

// BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean
BlobRange range = new BlobRange(1024, 2048L);
DownloadRetryOptions options = new DownloadRetryOptions().setMaxRetryRequests(5);

client.downloadToFileWithResponse(file, range, null, options, null, false)
.subscribe(response -> System.out.println("Completed download to file"));
// END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean

// BEGIN: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Set
BlobRange blobRange = new BlobRange(1024, 2048L);
DownloadRetryOptions downloadRetryOptions = new DownloadRetryOptions().setMaxRetryRequests(5);
Set<OpenOption> openOptions = new HashSet<>(Arrays.asList(StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE, StandardOpenOption.READ)); // Default options

client.downloadToFileWithResponse(file, blobRange, null, downloadRetryOptions, null, false, openOptions)
.subscribe(response -> System.out.println("Completed download to file"));
// END: com.azure.storage.blob.specialized.BlobAsyncClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Set
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* Code snippets for {@link BlobClientBase}
Expand Down Expand Up @@ -110,6 +115,12 @@ public void downloadToFile() {
System.out.println("Completed download to file");
// END: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String

// BEGIN: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String-boolean
boolean overwrite = false; // Default value
client.downloadToFile(file, overwrite);
System.out.println("Completed download to file");
// END: com.azure.storage.blob.specialized.BlobClientBase.downloadToFile#String-boolean

// BEGIN: com.azure.storage.blob.specialized.BlobClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Duration-Context
BlobRange range = new BlobRange(1024, 2048L);
DownloadRetryOptions options = new DownloadRetryOptions().setMaxRetryRequests(5);
Expand All @@ -118,6 +129,17 @@ public void downloadToFile() {
options, null, false, timeout, new Context(key2, value2));
System.out.println("Completed download to file");
// END: com.azure.storage.blob.specialized.BlobClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Duration-Context

// BEGIN: com.azure.storage.blob.specialized.BlobClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Set-Duration-Context
BlobRange blobRange = new BlobRange(1024, 2048L);
DownloadRetryOptions downloadRetryOptions = new DownloadRetryOptions().setMaxRetryRequests(5);
Set<OpenOption> openOptions = new HashSet<>(Arrays.asList(StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE, StandardOpenOption.READ)); // Default options

client.downloadToFileWithResponse(file, blobRange, new ParallelTransferOptions(4 * Constants.MB, null, null),
downloadRetryOptions, null, false, openOptions, timeout, new Context(key2, value2));
System.out.println("Completed download to file");
// END: com.azure.storage.blob.specialized.BlobClientBase.downloadToFileWithResponse#String-BlobRange-ParallelTransferOptions-DownloadRetryOptions-BlobRequestConditions-boolean-Set-Duration-Context
}

/**
Expand Down
Loading