WebロールからAzure Storage APIを使用してAzure Storage Blobの名前を変更することはできますか?現時点で私が持っている唯一の解決策は、正しい名前の新しいblobにblobをコピーし、古いものを削除することです。
そのための実用的な方法 がありますが、Azure Blob Service API は、BLOBの名前変更または移動機能を直接サポートしていません。
更新:
@IsaacAbrahamsコメントと@Viggityの回答の後でコードを更新しました。このバージョンでは、すべてをMemoryStreamにロードする必要がなくなり、コピーが完了するまで待機してからソースBLOBを削除します。
パーティーに遅れたものの、Azure Storage API V2を使用してこの投稿を偶然見つけた人のために、これをすばやく簡単に行う拡張メソッドを示します(+非同期バージョン)。
public static class BlobContainerExtensions
{
public static void Rename(this CloudBlobContainer container, string oldName, string newName)
{
//Warning: this Wait() is bad practice and can cause deadlock issues when used from ASP.NET applications
RenameAsync(container, oldName, newName).Wait();
}
public static async Task RenameAsync(this CloudBlobContainer container, string oldName, string newName)
{
var source = await container.GetBlobReferenceFromServerAsync(oldName);
var target = container.GetBlockBlobReference(newName);
await target.StartCopyFromBlobAsync(source.Uri);
while (target.CopyState.Status == CopyStatus.Pending)
await Task.Delay(100);
if (target.CopyState.Status != CopyStatus.Success)
throw new Exception("Rename failed: " + target.CopyState.Status);
await source.DeleteAsync();
}
}
Azure Storage 7.0の更新
public static async Task RenameAsync(this CloudBlobContainer container, string oldName, string newName)
{
CloudBlockBlob source =(CloudBlockBlob)await container.GetBlobReferenceFromServerAsync(oldName);
CloudBlockBlob target = container.GetBlockBlobReference(newName);
await target.StartCopyAsync(source);
while (target.CopyState.Status == CopyStatus.Pending)
await Task.Delay(100);
if (target.CopyState.Status != CopyStatus.Success)
throw new Exception("Rename failed: " + target.CopyState.Status);
await source.DeleteAsync();
}
免責事項:これは、名前の変更を同期的に実行させるための迅速で汚い方法です。それは私の目的に適合しますが、他のユーザーが指摘したように、コピーには長い時間がかかる場合があるため(この場合、数日まで)、最善の方法は、この回答のような1つの方法でこれを実行するのではなく、次のようにします。
ただし、コピーしてから削除することはできます。
私は元々@Zidadのコードを使用しており、低負荷の状況では通常それが機能しました(ほとんどの場合、小さいファイルの名前を変更します、最大10kb)。
StartCopyFromBlob
しないでくださいDelete
!!!!!!!!!!!!!!
高負荷のシナリオでは、名前を変更していたファイルの20%未満(数千のファイル)が失われます。彼の回答のコメントで述べたように、StartCopyFromBlob
はコピーを開始するだけです。 コピーが完了するのを待つ方法はありません。
コピーの完了を保証する唯一の方法は、コピーをダウンロードして再アップロードすることです。これが私の更新されたコードです:
public void Rename(string containerName, string oldFilename, string newFilename)
{
var oldBlob = GetBlobReference(containerName, oldFilename);
var newBlob = GetBlobReference(containerName, newFilename);
using (var stream = new MemoryStream())
{
oldBlob.DownloadToStream(stream);
stream.Seek(0, SeekOrigin.Begin);
newBlob.UploadFromStream(stream);
//copy metadata here if you need it too
oldBlob.Delete();
}
}
これは古い投稿ですが、おそらく 優れたブログ投稿 は、アップロードされたblobの名前をすばやく変更する方法を他のユーザーに示します。
ここにハイライトがあります:
//set the Azure container
string blobContainer = "myContainer";
//Azure connection string
string dataCenterSettingKey = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", "xxxx",
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
//setup the container object
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(dataCenterSettingKey);
CloudBlobClient blobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(blobContainer);
// Set permissions on the container.
BlobContainerPermissions permissions = new BlobContainerPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(permissions);
//grab the blob
CloudBlob existBlob = container.GetBlobReference("myBlobName");
CloudBlob newBlob = container.GetBlobReference("myNewBlobName");
//create a new blob
newBlob.CopyFromBlob(existBlob);
//delete the old
existBlob.Delete();
Blobをコピーしてから削除します。
1Gサイズのファイルでテストされ、問題なく動作します。
詳細については、MSDNの sample を参照してください。
StorageCredentials cred = new StorageCredentials("[Your?storage?account?name]", "[Your?storage?account?key]");
CloudBlobContainer container = new CloudBlobContainer(new Uri("http://[Your?storage?account?name].blob.core.windows.net/[Your container name] /"), cred);
string fileName = "OldFileName";
string newFileName = "NewFileName";
await container.CreateIfNotExistsAsync();
CloudBlockBlob blobCopy = container.GetBlockBlobReference(newFileName);
if (!await blobCopy.ExistsAsync())
{
CloudBlockBlob blob = container.GetBlockBlobReference(fileName);
if (await blob.ExistsAsync())
{
// copy
await blobCopy.StartCopyAsync(blob);
// then delete
await blob.DeleteIfExistsAsync();
}
}
これは、ファイルサイズが100 MB以下の100Kユーザーのライブ環境で私に役立ちました。これは、@ viggityの回答と同様の同期アプローチです。ただし、違いは、Azure側ですべてをコピーするため、新しいBlobにコピー/アップロードするためにサーバーにMemorystreamを保持する必要がないことです。
var account = new CloudStorageAccount(new Microsoft.WindowsAzure.Storage.Auth.StorageCredentials(StorageAccountName, StorageAccountKey), true);
CloudBlobClient blobStorage = account.CreateCloudBlobClient();
CloudBlobContainer container = blobStorage.GetContainerReference("myBlobContainer");
string fileName = "OldFileName";
string newFileName = "NewFileName";
CloudBlockBlob oldBlob = container.GetBlockBlobReference(fileName);
CloudBlockBlob newBlob = container.GetBlockBlobReference(newFileName);
using (var stream = new MemoryStream())
{
newBlob.StartCopyFromBlob(oldBlob);
do { } while (!newBlob.Exists());
oldBlob.Delete();
}
ContentDispositionプロパティを
attachment;filename="yourfile.txt"
Httpを介したダウンロードの名前は、任意の名前になります。
ストレージは、主にファイル名として使用される一意の識別子を使用してデータが格納されることを想定して構築されたと思います。すべてのダウンロードに対して共有アクセス署名を発行するのは少し奇妙なので、これは一部の人にとって理想的ではありません。
しかし、ユーザー向けのファイル名を抽象化することは全体的に良い習慣であり、全体としてより安定したアーキテクチャを奨励すると思います。
唯一の方法は、src blobを新しい宛先/名前に移動することです。これはこれを行うための私のコードです
public async Task<CloudBlockBlob> RenameAsync(CloudBlockBlob srcBlob, CloudBlobContainer destContainer,string name)
{
CloudBlockBlob destBlob;
if (srcBlob == null && srcBlob.Exists())
{
throw new Exception("Source blob cannot be null and should exist.");
}
if (!destContainer.Exists())
{
throw new Exception("Destination container does not exist.");
}
//Copy source blob to destination container
destBlob = destContainer.GetBlockBlobReference(name);
await destBlob.StartCopyAsync(srcBlob);
//remove source blob after copy is done.
srcBlob.Delete();
return destBlob;
}
メソッドの一部としてblobルックアップが必要な場合のコードサンプルを以下に示します。
public CloudBlockBlob RenameBlob(string oldName, string newName, CloudBlobContainer container)
{
if (!container.Exists())
{
throw new Exception("Destination container does not exist.");
}
//Get blob reference
CloudBlockBlob sourceBlob = container.GetBlockBlobReference(oldName);
if (sourceBlob == null && sourceBlob.Exists())
{
throw new Exception("Source blob cannot be null and should exist.");
}
// Get blob reference to which the new blob must be copied
CloudBlockBlob destBlob = container.GetBlockBlobReference(newName);
destBlob.StartCopyAsync(sourceBlob);
//Delete source blob
sourceBlob.Delete();
return destBlob;
}
BLOBをコピーして名前を変更したり、スクリプトを実行したりせずに、Azure BlobストレージをOSにマウントする方法もあります。 https://docs.Microsoft.com/bs-latn-ba/Azure/storage/blobs/storage-how-to-mount-container-linux
次に、mv
を使用するだけで、BLOBの名前が即座に変更されます。
ADLS Gen 2 ( Azure Data Lake Storage Gen 2 )のパブリックプレビューで新しいリリースを使用できるようになりました
階層的な名前空間 機能を使用すると、Rename操作を含むディレクトリとファイルのアトミック操作を実行できます。
ただし、次の点に注意してください。「プレビューリリースでは、階層名前空間を有効にすると、BlobとData Lake Storage Gen2の間でデータまたは操作の相互運用性がなくなります。REST API。この機能プレビュー中に追加されます。」
ADLS Gen 2を使用してBLOB(ファイル)を作成し、名前を変更する必要があります。それ以外の場合は、プレビュー期間中にBlob APIとADLS Gen 2の相互運用性が追加されるのを待ちます。