有没有办法停止或取消 python 中的 urlretrieve?
Is there a way to stop or cancel a urlretrieve in python?
所以我基本上使用 tkinter 和 urllib.request 在 python 中编写了一个程序 ,它应该作为下载器工作,但每个下载器都必须有一个暂停或取消按钮,但我似乎无法找到这样做!最近我在 Whosebug( link: Is it possible to stop (cancel) urlretrieve process?) 中遇到了同样的问题,似乎我必须使用 threads 或 multi-processing 但我不不知道如何做到这一点!顺便问一下,线程或多处理如何帮助取消暂停下载?有人可以向我解释我应该怎么做吗?无论如何,没有线程或多处理就可以做到这一点吗?如果没有,您能否解释一下如何在此程序中使用线程或多处理,因为我完全不知道该怎么做!请帮我解决这个问题。
我的代码:
from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
def printsth():
print("Yay it works! ")
def main_menu():
root = Tk()
root.title('8-bit downloader ')
root.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
root.geometry("600x280")
# the top menu
num = IntVar()
chum = IntVar()
# var = IntVar()
menu = Menu(root)
root.config(menu=menu)
submenu = Menu(menu)
menu.add_cascade(label="Settings", menu=submenu)
def custom_op():
custom = Toplevel()
custom.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
submenu.add_command(label="Customization ", command=custom_op)
def settings_op():
global gps
set_win = Toplevel()
set_win.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
path_label = Label(set_win, text="Current default download path: ")
path_entry = Entry(set_win, width=30)
file_read = open('Data.txt', 'r')
data_base = file_read.read()
path_entry.insert(0, data_base)
file_read.close()
def default_output():
global location
file_read2 = open('Data.txt', 'r+')
file_read2.truncate(0)
file_read2.close()
write_file2 = open('Data.txt', 'w')
write_file2.write(path_entry.get())
write_file2.close()
location = path_entry.get() + "\"
default_location = location.replace("\", "\\")
path_btn = Button(set_win, text="Submit ", command=default_output)
path_label.pack(anchor=CENTER, expand=1)
path_entry.pack(anchor=CENTER, expand=1)
path_btn.pack(anchor=CENTER, expand=1)
submenu.add_command(label="Settings ", command=settings_op)
submenu.add_separator()
submenu.add_command(label="Exit", command=root.destroy)
# the section menu
editmenu = Menu(menu)
menu.add_cascade(label="Sections(soon)", menu=editmenu)
editmenu.add_command(label="Downloader", command=printsth)
editmenu.add_command(label="Converter", command=printsth)
editmenu.add_command(label="Media Player", command=printsth)
editmenu.add_command(label="Editor", command=printsth)
# the tool bar
toolbar = Frame(root, bg="light gray")
insert_button = Button(toolbar, text="Insert an image", command=printsth)
insert_button.pack(side=LEFT, padx=2, pady=2)
print_button = Button(toolbar, text="Print", command=printsth)
print_button.pack(side=LEFT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
# the download function
def download_image():
global formatname
if num.get() == 1:
name = random.randrange(1, 1000000)
else:
name = str(name_entry.get())
formatname = str(format_entry.get())
'''if var.get() == 1:
operator = str(url_entry.get())
formatname = '.' + operator[-3] + operator[-2] + operator[-1]
else:
pass'''
fullname = str(name) + formatname
url = str(url_entry.get())
fw = open('file-size.txt', 'w')
file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
fw.write(str(file_size))
fw.close()
if chum.get() == 1:
filee = open('Data.txt', 'r')
destination = filee.read()
path = destination
output_entry.insert(0, destination)
filee.close()
else:
output_entry.delete(0, END)
path = str(output_entry.get()) + "\"
urllib.request.urlretrieve(url, path.replace("\", "\\") + fullname)
# the status bar
status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(root, bg="light blue")
download_button = Button(body_frame, text="Download! ", command=download_image, border=3, width=20, height=5)
download_design = tkFont.Font(size=12, slant='italic')
download_button['font'] = download_design
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
# the main interaction menu
inter_frame = Frame(root)
url_entry = Entry(inter_frame, width=30)
label = Label(inter_frame, text="Enter the image URL: ")
file_format = Label(inter_frame, text="Choose your file format: ")
format_entry = Entry(inter_frame, width=30)
file_name = Label(inter_frame, text="File's name: ")
name_entry = Entry(inter_frame, width=30)
check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
# check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
check_default = Checkbutton(inter_frame, text="Download to default path", variable=chum)
output_path = Label(inter_frame, text="Choose output path: ")
output_entry = Entry(inter_frame, width=30)
file_name.pack(anchor=CENTER, expand=1)
name_entry.pack(anchor=CENTER, expand=1)
check_name.pack(anchor=CENTER, expand=1)
label.pack(anchor=CENTER, expand=1)
url_entry.pack(anchor=CENTER, expand=1)
file_format.pack(anchor=CENTER, expand=1)
format_entry.pack(anchor=CENTER, expand=1)
format_entry.insert(0, '.')
# check_format.pack(anchor=CENTER)
output_path.pack(anchor=CENTER, expand=1)
output_entry.pack(anchor=CENTER, expand=1)
check_default.pack(anchor=CENTER, expand=1)
inter_frame.pack(expand=1)
root.mainloop()
# the end!
main_menu()
当运行像urlretrieve
这样的函数在单个线程或进程中时,没有办法停止它,因为只有一个线程或过程。
在这种情况下,您从 tkinter
回调 调用 urlretrieve
。这些由 tkinter 从 mainloop
调用,有效地中断了 mainloop
.
对于从快速连接的主机下载的小文件来说,这可能不是问题。但是,如果下载需要几秒钟或几分钟,那么您就有问题了。因为当 urlretrieve
正在进行时,您的 GUI 没有响应,因为 mainloop
正在等待您的回调完成。
因此,即使您有一个 "Cancel" 按钮,只要 urlretrieve
是 运行,它 就不会响应 。
从 Python 目录中的文件 urllib/request.py
中读取 urlretrieve
函数。这不是一个很大的功能,应该相对容易理解。
在内部,urlretrieve
包含一个循环,该循环 read
来自 URL 并写入文件。默认情况下,此类读取 等待 直到有任何内容可读取。事情是;没有办法中断这个循环。
所以无论如何,您将不得不重新编写 urlretrieve。在这个重写的版本中,如果您应该继续,您应该检查内部循环的每次迭代。
你基本上有两个选择;
- 将
urlretrieve
的功能应用到事件循环中。
- 将
urlretrieve
的功能放到另一个线程中。
各有优缺点。如果您正在使用 Python 3,启动 threading.Thread
可能是最简单的事情,因为 Python 3 中的 tkinter
是线程安全的。
有关第一种方法的示例,请参阅我在 github 上的脚本库中的 unlock-excel.pyw
。在此应用程序中,一个长操作被分成几个小步骤,这些步骤通过 after
方法从 tkinter
事件循环中调用。
对于使用线程的方法,我没有方便的示例。基本上你必须重写 urlretrieve
来检查一个变量(例如 threading.Event
),它发出信号是否应该在内部 while
循环中停止。
所以我基本上使用 tkinter 和 urllib.request 在 python 中编写了一个程序 ,它应该作为下载器工作,但每个下载器都必须有一个暂停或取消按钮,但我似乎无法找到这样做!最近我在 Whosebug( link: Is it possible to stop (cancel) urlretrieve process?) 中遇到了同样的问题,似乎我必须使用 threads 或 multi-processing 但我不不知道如何做到这一点!顺便问一下,线程或多处理如何帮助取消暂停下载?有人可以向我解释我应该怎么做吗?无论如何,没有线程或多处理就可以做到这一点吗?如果没有,您能否解释一下如何在此程序中使用线程或多处理,因为我完全不知道该怎么做!请帮我解决这个问题。 我的代码:
from tkinter import *
from tkinter import font as tkFont
import random
import urllib.request
import requests
def printsth():
print("Yay it works! ")
def main_menu():
root = Tk()
root.title('8-bit downloader ')
root.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
root.geometry("600x280")
# the top menu
num = IntVar()
chum = IntVar()
# var = IntVar()
menu = Menu(root)
root.config(menu=menu)
submenu = Menu(menu)
menu.add_cascade(label="Settings", menu=submenu)
def custom_op():
custom = Toplevel()
custom.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
submenu.add_command(label="Customization ", command=custom_op)
def settings_op():
global gps
set_win = Toplevel()
set_win.iconbitmap(r"C:\Users\rayanravesh\PycharmProjects\GUI_Calculator\icon.ico")
path_label = Label(set_win, text="Current default download path: ")
path_entry = Entry(set_win, width=30)
file_read = open('Data.txt', 'r')
data_base = file_read.read()
path_entry.insert(0, data_base)
file_read.close()
def default_output():
global location
file_read2 = open('Data.txt', 'r+')
file_read2.truncate(0)
file_read2.close()
write_file2 = open('Data.txt', 'w')
write_file2.write(path_entry.get())
write_file2.close()
location = path_entry.get() + "\"
default_location = location.replace("\", "\\")
path_btn = Button(set_win, text="Submit ", command=default_output)
path_label.pack(anchor=CENTER, expand=1)
path_entry.pack(anchor=CENTER, expand=1)
path_btn.pack(anchor=CENTER, expand=1)
submenu.add_command(label="Settings ", command=settings_op)
submenu.add_separator()
submenu.add_command(label="Exit", command=root.destroy)
# the section menu
editmenu = Menu(menu)
menu.add_cascade(label="Sections(soon)", menu=editmenu)
editmenu.add_command(label="Downloader", command=printsth)
editmenu.add_command(label="Converter", command=printsth)
editmenu.add_command(label="Media Player", command=printsth)
editmenu.add_command(label="Editor", command=printsth)
# the tool bar
toolbar = Frame(root, bg="light gray")
insert_button = Button(toolbar, text="Insert an image", command=printsth)
insert_button.pack(side=LEFT, padx=2, pady=2)
print_button = Button(toolbar, text="Print", command=printsth)
print_button.pack(side=LEFT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
# the download function
def download_image():
global formatname
if num.get() == 1:
name = random.randrange(1, 1000000)
else:
name = str(name_entry.get())
formatname = str(format_entry.get())
'''if var.get() == 1:
operator = str(url_entry.get())
formatname = '.' + operator[-3] + operator[-2] + operator[-1]
else:
pass'''
fullname = str(name) + formatname
url = str(url_entry.get())
fw = open('file-size.txt', 'w')
file_size = int(requests.head(url, headers={'accept-encoding': ''}).headers['Content-Length'])
fw.write(str(file_size))
fw.close()
if chum.get() == 1:
filee = open('Data.txt', 'r')
destination = filee.read()
path = destination
output_entry.insert(0, destination)
filee.close()
else:
output_entry.delete(0, END)
path = str(output_entry.get()) + "\"
urllib.request.urlretrieve(url, path.replace("\", "\\") + fullname)
# the status bar
status_bar = Label(root, text="Downloading...", bd=1, relief=SUNKEN, anchor=W)
status_bar.pack(side=BOTTOM, fill=X)
# the download frame
body_frame = Frame(root, bg="light blue")
download_button = Button(body_frame, text="Download! ", command=download_image, border=3, width=20, height=5)
download_design = tkFont.Font(size=12, slant='italic')
download_button['font'] = download_design
download_button.pack(side=LEFT, pady=5, padx=5)
body_frame.pack(side=LEFT, fill=Y)
# the main interaction menu
inter_frame = Frame(root)
url_entry = Entry(inter_frame, width=30)
label = Label(inter_frame, text="Enter the image URL: ")
file_format = Label(inter_frame, text="Choose your file format: ")
format_entry = Entry(inter_frame, width=30)
file_name = Label(inter_frame, text="File's name: ")
name_entry = Entry(inter_frame, width=30)
check_name = Checkbutton(inter_frame, text="Give a random name", variable=num)
# check_format = Checkbutton(inter_frame, text="Download with default format", variable=var)
check_default = Checkbutton(inter_frame, text="Download to default path", variable=chum)
output_path = Label(inter_frame, text="Choose output path: ")
output_entry = Entry(inter_frame, width=30)
file_name.pack(anchor=CENTER, expand=1)
name_entry.pack(anchor=CENTER, expand=1)
check_name.pack(anchor=CENTER, expand=1)
label.pack(anchor=CENTER, expand=1)
url_entry.pack(anchor=CENTER, expand=1)
file_format.pack(anchor=CENTER, expand=1)
format_entry.pack(anchor=CENTER, expand=1)
format_entry.insert(0, '.')
# check_format.pack(anchor=CENTER)
output_path.pack(anchor=CENTER, expand=1)
output_entry.pack(anchor=CENTER, expand=1)
check_default.pack(anchor=CENTER, expand=1)
inter_frame.pack(expand=1)
root.mainloop()
# the end!
main_menu()
当运行像urlretrieve
这样的函数在单个线程或进程中时,没有办法停止它,因为只有一个线程或过程。
在这种情况下,您从 tkinter
回调 调用 urlretrieve
。这些由 tkinter 从 mainloop
调用,有效地中断了 mainloop
.
对于从快速连接的主机下载的小文件来说,这可能不是问题。但是,如果下载需要几秒钟或几分钟,那么您就有问题了。因为当 urlretrieve
正在进行时,您的 GUI 没有响应,因为 mainloop
正在等待您的回调完成。
因此,即使您有一个 "Cancel" 按钮,只要 urlretrieve
是 运行,它 就不会响应 。
从 Python 目录中的文件 urllib/request.py
中读取 urlretrieve
函数。这不是一个很大的功能,应该相对容易理解。
在内部,urlretrieve
包含一个循环,该循环 read
来自 URL 并写入文件。默认情况下,此类读取 等待 直到有任何内容可读取。事情是;没有办法中断这个循环。
所以无论如何,您将不得不重新编写 urlretrieve。在这个重写的版本中,如果您应该继续,您应该检查内部循环的每次迭代。
你基本上有两个选择;
- 将
urlretrieve
的功能应用到事件循环中。 - 将
urlretrieve
的功能放到另一个线程中。
各有优缺点。如果您正在使用 Python 3,启动 threading.Thread
可能是最简单的事情,因为 Python 3 中的 tkinter
是线程安全的。
有关第一种方法的示例,请参阅我在 github 上的脚本库中的 unlock-excel.pyw
。在此应用程序中,一个长操作被分成几个小步骤,这些步骤通过 after
方法从 tkinter
事件循环中调用。
对于使用线程的方法,我没有方便的示例。基本上你必须重写 urlretrieve
来检查一个变量(例如 threading.Event
),它发出信号是否应该在内部 while
循环中停止。