有没有办法从 Windows Azure 的 blob 存储中的文本文件中逐行读取?
谢谢
是的,你可以用流来做到这一点,它不一定需要你拉整个文件,但请阅读到最后(答案的......不是有问题的文件),因为你可能想拉整个文件反正文件。
这是代码:
StorageCredentialsAccountAndKey credentials = new StorageCredentialsAccountAndKey(
"YourStorageAccountName",
"YourStorageAccountKey"
);
CloudStorageAccount account = new CloudStorageAccount(credentials, true);
CloudBlobClient client = new CloudBlobClient(account.BlobEndpoint.AbsoluteUri, account.Credentials);
CloudBlobContainer container = client.GetContainerReference("test");
CloudBlob blob = container.GetBlobReference("CloudBlob.txt");
using (var stream = blob.OpenRead())
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
Console.WriteLine(reader.ReadLine());
}
}
}
我将一个名为 CloudBlob.txt 的文本文件上传到了一个名为 test 的容器中。该文件大小约为 1.37 MB(我实际上使用了 GitHub 上的 CloudBlob.cs 文件,将其复制到同一个文件中六七次)。我使用 BlockBlob 进行了尝试,这很可能是您将要处理的内容,因为您正在谈论一个文本文件。
这会像往常一样获得对 BLOB 的引用,然后我从 CloudBlob 对象中调用OpenRead () 方法,该方法会返回一个 BlobStream ,然后您可以将其包装在 StreamReader 中以获得 ReadLine 方法。我用这个运行 fiddler 并注意到它最终调用了 3 次来获取额外的块来完成文件。看起来 BlobStream 有一些属性,您可以使用这些属性来调整您必须执行的预读量,但我没有尝试调整它们。根据一个参考资料,我发现重试策略也适用于最后一次读取级别,因此它不会再次尝试重新读取整个内容,只是最后一次失败的请求。在此引用:
最后,DownloadToFile/ByteArray/Stream/Text() 方法在单个流式获取中执行它的整个下载。如果您使用 CloudBlob.OpenRead() 方法,它将利用 BlobReadStream 抽象,该抽象将在消耗 Blob 时一次下载一个块。如果发生连接错误,则只需要重新下载一个块(根据配置的 RetryPolicy)。此外,这可能有助于提高性能,因为客户端可能不需要在本地缓存大量数据。对于大型 blob,这可能会有很大帮助,但请注意,您将对服务执行更多的整体事务。——乔·贾迪诺
我认为重要的是要注意 Joe 指出的警告,因为这将导致针对您的存储帐户的总体交易数量增加。 但是,根据您的要求,这可能仍然是您正在寻找的选项。
如果这些是大量文件并且您正在执行大量此类操作,那么它可能会执行很多很多事务(尽管您可以查看是否可以调整 BlobStream 上的属性以增加一次检索的块数量等)。在 CloudBlob 上执行 DownloadFromStream 可能仍然有意义(这将拉下整个内容),然后以与我上面相同的方式从该流中读取。
唯一真正的区别是,一个是一次提取较小的块,另一个是立即提取整个文件。每个都有优点和缺点,这在很大程度上取决于这些文件的大小以及您是否计划在读取文件中间的某个时间点停止(例如“是的,我找到了我正在搜索的字符串!)或者如果您仍然打算读取整个文件。如果您打算无论如何都提取整个文件(例如,因为您正在处理整个文件),那么只需使用 DownloadToStream 并将其包装在 StreamReader 中。
注意:我用 1.7 SDK 试过这个。我不确定这些选项是由哪个 SDK 引入的。
要直接回答您的问题,您必须先编写代码以在本地下载 blob,然后再读取其中的内容。这主要是因为您不能只进入一个 blob 并在中间读取它的内容。如果您使用过 Windows Azure 表存储,您肯定可以读取表中的具体内容。
由于您的文本文件是一个 blob 并且位于 Azure Blob 存储中,因此您真正需要的是在本地下载 blob(作为本地 blob 或内存流),然后读取其中的内容。您必须完全或部分下载 blob,具体取决于您上传的 blob 类型。使用页面 blob,您可以在本地下载特定大小的内容并对其进行处理。很高兴知道在这方面块和页面 blob 之间的区别。
这是我用来逐行获取文件的代码。该文件存储在 Azure 存储中。使用了文件服务而不是 blob 服务。
//https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-files
//https://<storage account>.file.core.windows.net/<share>/<directory/directories>/<file>
public void ReadAzureFile() {
CloudStorageAccount account = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudFileClient fileClient = account.CreateCloudFileClient();
CloudFileShare share = fileClient.GetShareReference("jiosongdetails");
if (share.Exists()) {
CloudFileDirectory rootDir = share.GetRootDirectoryReference();
CloudFile file = rootDir.GetFileReference("songdetails(1).csv");
if (file.Exists()) {
using(var stream = file.OpenRead()) {
using(StreamReader reader = new StreamReader(stream)) {
while (!reader.EndOfStream) {
Console.WriteLine(reader.ReadLine());
}
}
}
}
}
如果有人发现自己在这里,适用于 Azure Blob 存储 (v12) 的 Python SDK 现在有一个简单的download_blob()
方法,它接受两个参数 - 偏移量和长度。
使用 Python,我的目标是从 blob 存储中的(许多)文件中提取标题行。我知道所有文件的位置,所以我创建了一个 blob 客户端列表——每个文件一个。然后,我遍历列表并运行 download_blob 方法。
创建 Blob 客户端后(直接通过连接字符串或使用BlobServiceClient.get_blob_client()
方法),只需下载前(例如)4k 字节以覆盖任何长标题行,然后使用行尾字符 ('\n ')。结果列表的第一个元素将是标题行。我的工作代码(仅针对单个文件)如下所示:
from azure.storage.blob import BlobServiceClient
MAX_LINE_SIZE = 4096 # You can change this..
my_blob_service_client = BlobServiceClient(account_url=my_url, credential=my_shared_access_key)
my_blob_client = my_blob_service_client.get_blob_client('my-container','my_file.csv')
file_size = my_blob_client.size
offset = 0
然后,您可以编写一个循环来逐行下载文本,方法是计算第一个行尾的字节偏移量,并获取下一个 MAX_LINE_SIZE 个字节。为了获得最佳效率,最好知道一条线的最大长度,但如果你不知道,请猜测一个足够大的长度。
while offset < file_size - 1:
next_text_block = my_blob_client.download_blob(offset=offset, length=MAX_LINE_SIZE)
line = next_text_block.split('\n')[0]
offset = len(line) + 1
# Do something with your line..
希望有帮助。这里明显的权衡是网络开销,每次调用一行文本并不快,但它达到了你逐行阅读的要求。