python - 如何使用 Python 为 Azure 文件存储使用获取文件属性 REST API
问题描述
我正在尝试创建一个 Python 脚本,该脚本将同时利用适用于 Azure 的 Python SDK 和 REST API,以便为我的 Azure 文件存储帐户中的文件提取信息。
我正在使用 SDK 访问存储中的文件并获取名称。然后使用我希望能够调用 REST API 来获取文件属性的名称,特别是 Last-Modified 属性。我尝试使用 SDK 访问最后修改的属性,但由于某种原因它总是返回 None。
我想使用上次修改日期来确定它是否超过 24 小时,如果超过了,那么我想删除该文件。当我第一次创建文件并将其上传到天蓝色时,我不确定是否可以在文件的某个时间段属性后设置某种自动删除。如果有,那么无论如何这将解决我的问题。
我在下面发布了我正在使用的代码。当我尝试发出 HTTP 请求时,我收到错误消息“服务器无法对请求进行身份验证。确保授权标头的值正确形成,包括签名。”
import datetime
import requests
import json
import base64
import hmac
import hashlib
import urllib
from azure.storage.file import *
StorageAccountConnectionString = ""
fileshareName = "testFileShare"
storage_account_name = "testStorage"
storage_account_key = ""
api_version = "2018-03-28"
file_service = FileService(connection_string=StorageAccountConnectionString)
listOfStateDirectories = file_service.list_directories_and_files(fileshareName)
for state_directory in listOfStateDirectories:
print("Cleaning up State Directory: " + state_directory.name)
if(isinstance(state_directory, Directory)):
listOfBridgeDirectories = file_service.list_directories_and_files(fileshareName, state_directory.name)
for bridge_directory in listOfBridgeDirectories:
if(isinstance(bridge_directory, Directory)):
print("Cleaning up Bridge Directory: " + bridge_directory.name)
path_to_bridge_directory = state_directory.name + "/" + bridge_directory.name
listOfFilesAndFolders = file_service.list_directories_and_files(fileshareName, path_to_bridge_directory)
for file_or_folder in listOfFilesAndFolders:
if isinstance(file_or_folder, File):
name_of_file = file_or_folder.name
# Get the time of the current request
request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
string_to_append_to_url = fileshareName + '/' + path_to_bridge_directory + '/' + name_of_file
# Parse the url to make sure everything is good
# string_to_append_to_url = urllib.parse.quote(string_to_append_to_url)
string_params = {
'verb': 'HEAD',
'Content-Encoding': '',
'Content-Language': '',
'Content-Length': '',
'Content-MD5': '',
'Content-Type': '',
'Date': '',
'If-Modified-Since': '',
'If-Match': '',
'If-None-Match': '',
'If-Unmodified-Since': '',
'Range': '',
'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-version:' + api_version + '\n',
'CanonicalizedResource': '/' + storage_account_name + '/' + string_to_append_to_url
}
string_to_sign = (string_params['verb'] + '\n'
+ string_params['Content-Encoding'] + '\n'
+ string_params['Content-Language'] + '\n'
+ string_params['Content-Length'] + '\n'
+ string_params['Content-MD5'] + '\n'
+ string_params['Content-Type'] + '\n'
+ string_params['Date'] + '\n'
+ string_params['If-Modified-Since'] + '\n'
+ string_params['If-Match'] + '\n'
+ string_params['If-None-Match'] + '\n'
+ string_params['If-Unmodified-Since'] + '\n'
+ string_params['Range'] + '\n'
+ string_params['CanonicalizedHeaders']
+ string_params['CanonicalizedResource'])
signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
headers = {
'x-ms-date': request_time,
'x-ms-version': api_version,
'Authorization': ('SharedKey ' + storage_account_name + ':' + signed_string)
}
url = ('https://' + storage_account_name + '.file.core.windows.net/' + string_to_append_to_url)
print(url)
r = requests.get(url, headers=headers)
print(r.content)
注意:一些目录会有空格,所以我不确定这是否会影响 REST API 调用,因为 URL 也会有空格。如果它确实影响了它,那么我将如何访问那些 URL 将包含空格的文件
解决方案
我尝试使用 SDK 访问最后修改的属性,但由于某种原因它总是返回 None。
并非所有 SDK API 和 REST API 都会返回Last-Modified
响应标头中的属性,包括 REST APIList Directories and Files
和 Python SDK API list_directories_and_files
。
我尝试使用 SDK 重现您的问题,如下面的代码。
generator = file_service.list_directories_and_files(share_name, directory_name)
for file_or_dir in generator:
if isinstance(file_or_dir, File):
print(file_or_dir.name, file_or_dir.properties.last_modified)
由于该list_directories_and_files
方法不会返回File
对象中的任何属性,所以file_or_dir.properties.last_modified
上面代码的值为None
.
REST API Get File
、Get File Properties
和Get File Metadata
Python SDK API将在响应的标头get_file_properties
中get_file_metadata
返回Last-Modified
属性,因此要更改以下代码以获取last_modified
属性以使其工作。
generator = file_service.list_directories_and_files(share_name, directory_name)
for file_or_dir in generator:
if isinstance(file_or_dir, File):
file_name = file_or_dir.name
file = file_service.get_file_properties(share_name, directory_name, file_name, timeout=None, snapshot=None)
print(file_or_dir.name, file.properties.last_modified)
当然,调用 REST API 和使用 SDK API 是一样的。但是,构建 SAS 签名字符串容易出错,不利于阅读代码。
推荐阅读
- plotly - Plotly JS Python 跟踪名称标签被切断
- react-native - 如何检查 React Native Streetview 是否成功渲染了位置
- angular - Angular Reactive Forms 处理两个级别/维度的复选框
- pytest - 为不同的测试赋予 Pytest 固定装置不同的范围
- python - sklearn LogisticRegression:它是否使用多个后台线程?
- angular - Angular Share服务主题绑定问题
- python-3.x - 通过将其行与另一个数据框的多个级别匹配来填充数据框
- vuetify.js - 在 Vuepress 组件中使用 Vuetify
- uwp - 无法安装 UWP 侧载构建
- google-chrome - Chrome 扩展切换标签队列