如何在 python 中写入文件时打印 "dots"(或其他类型的反馈)?
How to print "dots" (or other kind of feedback) while writing a file in python?
当我的应用程序从网络上下载文件并将其写入硬盘时,我正在尝试在终端中为用户打印可见反馈,但我无法通过阅读文档或谷歌搜索找到如何执行此操作它。
这是我的代码:
res = requests.get(url_to_file)
with open("./downloads/%s" % (file_name), 'wb') as f:
f.write(res.content)
我期待弄清楚如何制作这样的东西:
Downloading file ........
# it keeps going ultil the download is finished and the file writen
Done!
我真的很难开始,因为 none 方法 returns 是一个“承诺”(就像在 JS 中一样)。
非常感谢任何帮助!
谢谢!
requests.get
默认情况下会在返回给您之前下载全部请求的资源。但是,它有一个可选参数 stream
,它允许您在 Response
对象上调用 .iter_content
或 .iter_lines
。这允许您分别在每 N 个字节(或每个数据块到达时)或每一行采取行动。像这样:
chunks = []
chunk_size = 16384 # 16Kb chunks
# alternately
# chunk_size = None # whenever a chunk arrives
res = requests.get(url_to_file, stream=True)
for chunk in res.iter_content(chunk_size):
chunks.append(chunk)
print(".", end="")
data = b''.join(chunks)
虽然这仍然是块,所以不会发生其他事情。如果你想要更多的 JavaScript 风格,根据 Grismar 的评论,你应该 运行 在 Python 的异步循环下。在这种情况下,我建议使用 aiohttp
而不是 requests
,因为它是在考虑异步样式的情况下创建的。
这是一个将文件下载到单独线程中的 bytearray
的版本。
正如其他答案和评论中所提到的,还有其他的替代方案是在考虑异步操作的情况下开发的,所以不要过多地解读使用 threading
的决定,这只是为了证明概念(并且因为方便,因为它带有 python)。
在下面的代码中,如果已知文件的大小,每个.
将对应1%。作为奖励,下载的字节数和总字节数将打印在行的开头,如 (1234 B / 1234567 B)
。如果大小未知,后备解决方案是让每个 .
代表一个块。
import requests
import threading
def download_file(url: str):
headers = {"<some_key>": "<some_value>"}
data = bytearray()
with requests.get(url, headers=headers, stream=True) as request:
if file_size := request.headers.get("Content-Length"):
file_size = int(file_size)
else:
file_size = None
received = 0
for chunk in request.iter_content(chunk_size=2**15):
received += len(chunk)
data += chunk
try:
num_dots = int(received * 100 / file_size)
print(
f"({received} B/{file_size} B) "
+ "." * num_dots, end="\r"
)
except TypeError:
print(".", end="")
print("\nDone!")
url = "<some_url>"
thread = threading.Thread(target=download_file, args=(url,))
thread.start()
# Do something in the meantime
thread.join()
请记住,我省略了锁以防止同时访问 stdout
以减少噪音。我也没有在最后将 bytarray
写入文件(或者如果文件很大,则在收到时将块写入文件),但请记住,您可能需要为此使用锁同样,如果您阅读 and/or 在脚本的任何其他部分写入同一文件。
当我的应用程序从网络上下载文件并将其写入硬盘时,我正在尝试在终端中为用户打印可见反馈,但我无法通过阅读文档或谷歌搜索找到如何执行此操作它。
这是我的代码:
res = requests.get(url_to_file)
with open("./downloads/%s" % (file_name), 'wb') as f:
f.write(res.content)
我期待弄清楚如何制作这样的东西:
Downloading file ........
# it keeps going ultil the download is finished and the file writen
Done!
我真的很难开始,因为 none 方法 returns 是一个“承诺”(就像在 JS 中一样)。
非常感谢任何帮助! 谢谢!
requests.get
默认情况下会在返回给您之前下载全部请求的资源。但是,它有一个可选参数 stream
,它允许您在 Response
对象上调用 .iter_content
或 .iter_lines
。这允许您分别在每 N 个字节(或每个数据块到达时)或每一行采取行动。像这样:
chunks = []
chunk_size = 16384 # 16Kb chunks
# alternately
# chunk_size = None # whenever a chunk arrives
res = requests.get(url_to_file, stream=True)
for chunk in res.iter_content(chunk_size):
chunks.append(chunk)
print(".", end="")
data = b''.join(chunks)
虽然这仍然是块,所以不会发生其他事情。如果你想要更多的 JavaScript 风格,根据 Grismar 的评论,你应该 运行 在 Python 的异步循环下。在这种情况下,我建议使用 aiohttp
而不是 requests
,因为它是在考虑异步样式的情况下创建的。
这是一个将文件下载到单独线程中的 bytearray
的版本。
正如其他答案和评论中所提到的,还有其他的替代方案是在考虑异步操作的情况下开发的,所以不要过多地解读使用 threading
的决定,这只是为了证明概念(并且因为方便,因为它带有 python)。
在下面的代码中,如果已知文件的大小,每个.
将对应1%。作为奖励,下载的字节数和总字节数将打印在行的开头,如 (1234 B / 1234567 B)
。如果大小未知,后备解决方案是让每个 .
代表一个块。
import requests
import threading
def download_file(url: str):
headers = {"<some_key>": "<some_value>"}
data = bytearray()
with requests.get(url, headers=headers, stream=True) as request:
if file_size := request.headers.get("Content-Length"):
file_size = int(file_size)
else:
file_size = None
received = 0
for chunk in request.iter_content(chunk_size=2**15):
received += len(chunk)
data += chunk
try:
num_dots = int(received * 100 / file_size)
print(
f"({received} B/{file_size} B) "
+ "." * num_dots, end="\r"
)
except TypeError:
print(".", end="")
print("\nDone!")
url = "<some_url>"
thread = threading.Thread(target=download_file, args=(url,))
thread.start()
# Do something in the meantime
thread.join()
请记住,我省略了锁以防止同时访问 stdout
以减少噪音。我也没有在最后将 bytarray
写入文件(或者如果文件很大,则在收到时将块写入文件),但请记住,您可能需要为此使用锁同样,如果您阅读 and/or 在脚本的任何其他部分写入同一文件。