Как печатать "точки" (или другой вид обратной связи) при написании файла на python?

0

Вопрос

Я пытаюсь напечатать видимую обратную связь для пользователя в терминале, в то время как мое приложение загружает файл из Интернета и записывает его на жесткий диск, но я не смог найти, как это сделать, прочитав документацию или погуглив ее.

Это мой код:

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!

Я действительно изо всех сил пытаюсь даже начать, потому что ни один из методов не возвращает "обещание" (как в JS).

Любая помощь была бы очень признательна! Спасибо!

file promise python
2021-11-24 05:40:54
2

Лучший ответ

3

requests.get по умолчанию загружается весь запрошенный ресурс, прежде чем он вернется к вам. Однако у него есть необязательный аргумент stream, что позволяет вам вызывать .iter_content или .iter_lines на Response объект. Это позволяет вам выполнять действия каждые 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, согласно комментарию Грисмара, вы должны работать в асинхронном цикле Python. В этом случае я предлагаю использоватьaiohttp скорее, чем requests, так как он создан с учетом асинхронного стиля.

2021-11-24 06:52:04

Большое вам спасибо за ваш ответ! Это было очень быстро! ха-ха, я сделал undestand и концепцию, и хорошо знать, что в python есть асинхронные функции. По какой-то причине, когда я попытался применить ваш код, он напечатал файлы только после завершения запроса. Возможно, я что-то упускаю...
guilfer
1

Вот версия, которая загрузит файл в 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 в файл в конце (или запись фрагментов в файл по мере их получения, если файл большой), но имейте в виду, что для этого также может потребоваться блокировка, если вы читаете и/или записываете в тот же файл в любой другой части вашего сценария.

2021-11-24 05:57:53

Это ужасно! Я думаю, что понимаю концепцию, но я довольно новичок в python, и я решил пойти простым путем, ха-ха, я закладываю ваш ответ в закладки, и как только я узнаю больше о потоковой передаче, я обязательно его обновлю! Большое спасибо!
guilfer

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................