试图要求输入文件并将其保存在特定位置
Trying to ask for a file input and save it in specific location
所以我正在尝试编写一种方法来保存用户选择的图片并将图片添加到父级 class 'activity'。这是我尝试过的:
# Creating object from filedialog
picture = filedialog.asksaveasfile(mode='r', title='Select activity picture', defaultextension=".jpg")
# Check if cancelled
if picture is None:
return
else:
folder_dir = 'main/data/activity_pics'
pic_name = 'rocket_league' #change to desc_to_img_name() later
path = os.path.join(folder_dir, f'{pic_name}')
# Making the folder if it does not exist yet
if not os.path.exists(folder_dir):
os.makedirs(folder_dir)
# Creating a location object
f = open(path, "a")
# Writing picture on location object
f.write(picture)
# Closing
f.close()
# Check if successful
if os.path.exists(path):
print(f'File saved as {pic_name} in directory {folder_dir}')
self.picture_path = path
后来,我使用 rocketleague.add_picture()
调用该方法,其中我将 rocketleague 定义为 Activity
class.
我尝试了在网上找到的几种不同的解决方案,但 none 似乎有效。目前,这个脚本报错:
C:\Users\timda\PycharmProjects\group-31\venv\Scripts\python.exe C:/Users/timda/PycharmProjects/group-31/project/activities/random_activity_generator.py
Traceback (most recent call last):
File "C:/Users/timda/PycharmProjects/group-31/project/activities/random_activity_generator.py", line 160, in <module>
rocketleague.add_picture()
File "C:/Users/timda/PycharmProjects/group-31/project/activities/random_activity_generator.py", line 46, in add_picture
f.write(picture)
TypeError: write() argument must be str, not _io.TextIOWrapper
所以我猜我的 open.write() 只适用于字符串。我不确定我目前的方法是否有效。
最方便的方法是什么?
根据您的描述,您正在使用完全不同的方法来完成任务。
我将首先解释您正在尝试做什么以及为什么它不起作用。
-> 因此,在您要求用户 select 文件并创建 folder_dir
和 path
之后,您想要 move/copy 图片 selected 到变量 path
.
描述的位置
问题,
- 根据您的需要,您可能就在这里,但我觉得您应该使用
filedialog.askopenfile()
而不是 filedialog.asksaveasfile()
,因为您可能希望它们 select 一个文件,而不是 select 将文件移动到的文件夹 - 您似乎已经有了目的地 folder_dir
。但这同样取决于您的需要。
- 重要的一个。在您的代码中,其中一条评论说:“”“创建位置对象”“”并且您使用了
f = open(path, "a")
,您没有在那里创建位置对象。 f
只是一个以文本附加模式打开的 file
对象 - 如 open()
函数调用中第二个参数中的 "a"
所示。您不能将二进制图像文件写入文本文件。这就是为什么错误消息说,它希望将字符串写入文本文件,而不是二进制 I/O Wrapper.
解决方案
很简单,使用实际方法移动文件来执行任务。
所以一旦你有了图像文件的地址(select 由用户在 filedialog
中编辑 - 上面解释过) - 请注意,正如@Bryan 指出的那样,picture
变量将始终file handler
用户编辑的文件 select。我们可以使用 file handler
.
的属性 .name
获取 selected 文件的绝对地址
>>> import tkinter.filedialog as fd
>>> a = fd.askopenfile()
# I selected a test.txt file
>>> a
<_io.TextIOWrapper name='C:/BeingProfessional/projects/Py/test.txt' mode='r' encoding='cp1252'>
# the type is neither a file, not an address.
>>> type(a)
<class '_io.TextIOWrapper'>
>>> import os
# getting the absolute address with name attribute
>>> print(a.name)
C:/BeingProfessional/projects/Py/test.txt
# check aith os.path
>>> os.path.exists(a.name)
True
注意:
我们还可以使用 filedialog.askopenfilename()
,其中 returns 只是文件的地址 select,这样您就不必担心文件处理程序及其属性。
我们已经有了目的地 folder_dir
和一个新的文件名。
这就是我们所需要的,一个来源和目的地。
这是复制文件的方法
这三种方法的作用相同。根据需要使用其中任何一个。
import os
import shutil
os.rename("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
os.replace("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
请注意,您必须在源参数和目标参数中都包含文件名 (file.foo)。如果更改,文件将被重命名和移动。
另请注意,在前两种情况下,创建新文件的目录必须已经存在。在 Windows 机器上,不能存在具有该名称的文件,否则将引发 exception
,但 os.replace()
即使在这种情况下也会自动替换文件。
您的代码已修改
# Creating object from filedialog
picture = filedialog.askopenfile(mode='r', title='Select activity picture', defaultextension=".jpg")
# Check if cancelled
if picture is None:
return
else:
folder_dir = 'main/data/activity_pics'
pic_name = 'rocket_league' #change to desc_to_img_name() later
path = os.path.join(folder_dir, f'{pic_name}')
# Making the folder if it does not exist yet
if not os.path.exists(folder_dir):
os.makedirs(folder_dir)
# the change here
shutil.move(picture.name, path) # using attribute to get abs address
# Check if successful
if os.path.exists(path):
print(f'File saved as {pic_name} in directory {folder_dir}')
self.picture_path = path
此代码块的缩进不是很好,因为原始问题格式没有缩进那么好。
感谢 Bryan 指出错误 :)
所以我正在尝试编写一种方法来保存用户选择的图片并将图片添加到父级 class 'activity'。这是我尝试过的:
# Creating object from filedialog
picture = filedialog.asksaveasfile(mode='r', title='Select activity picture', defaultextension=".jpg")
# Check if cancelled
if picture is None:
return
else:
folder_dir = 'main/data/activity_pics'
pic_name = 'rocket_league' #change to desc_to_img_name() later
path = os.path.join(folder_dir, f'{pic_name}')
# Making the folder if it does not exist yet
if not os.path.exists(folder_dir):
os.makedirs(folder_dir)
# Creating a location object
f = open(path, "a")
# Writing picture on location object
f.write(picture)
# Closing
f.close()
# Check if successful
if os.path.exists(path):
print(f'File saved as {pic_name} in directory {folder_dir}')
self.picture_path = path
后来,我使用 rocketleague.add_picture()
调用该方法,其中我将 rocketleague 定义为 Activity
class.
我尝试了在网上找到的几种不同的解决方案,但 none 似乎有效。目前,这个脚本报错:
C:\Users\timda\PycharmProjects\group-31\venv\Scripts\python.exe C:/Users/timda/PycharmProjects/group-31/project/activities/random_activity_generator.py
Traceback (most recent call last):
File "C:/Users/timda/PycharmProjects/group-31/project/activities/random_activity_generator.py", line 160, in <module>
rocketleague.add_picture()
File "C:/Users/timda/PycharmProjects/group-31/project/activities/random_activity_generator.py", line 46, in add_picture
f.write(picture)
TypeError: write() argument must be str, not _io.TextIOWrapper
所以我猜我的 open.write() 只适用于字符串。我不确定我目前的方法是否有效。
最方便的方法是什么?
根据您的描述,您正在使用完全不同的方法来完成任务。
我将首先解释您正在尝试做什么以及为什么它不起作用。
-> 因此,在您要求用户 select 文件并创建 folder_dir
和 path
之后,您想要 move/copy 图片 selected 到变量 path
.
问题,
- 根据您的需要,您可能就在这里,但我觉得您应该使用
filedialog.askopenfile()
而不是filedialog.asksaveasfile()
,因为您可能希望它们 select 一个文件,而不是 select 将文件移动到的文件夹 - 您似乎已经有了目的地folder_dir
。但这同样取决于您的需要。 - 重要的一个。在您的代码中,其中一条评论说:“”“创建位置对象”“”并且您使用了
f = open(path, "a")
,您没有在那里创建位置对象。f
只是一个以文本附加模式打开的file
对象 - 如open()
函数调用中第二个参数中的"a"
所示。您不能将二进制图像文件写入文本文件。这就是为什么错误消息说,它希望将字符串写入文本文件,而不是二进制 I/O Wrapper.
解决方案
很简单,使用实际方法移动文件来执行任务。
所以一旦你有了图像文件的地址(select 由用户在 filedialog
中编辑 - 上面解释过) - 请注意,正如@Bryan 指出的那样,picture
变量将始终file handler
用户编辑的文件 select。我们可以使用 file handler
.
.name
获取 selected 文件的绝对地址
>>> import tkinter.filedialog as fd
>>> a = fd.askopenfile()
# I selected a test.txt file
>>> a
<_io.TextIOWrapper name='C:/BeingProfessional/projects/Py/test.txt' mode='r' encoding='cp1252'>
# the type is neither a file, not an address.
>>> type(a)
<class '_io.TextIOWrapper'>
>>> import os
# getting the absolute address with name attribute
>>> print(a.name)
C:/BeingProfessional/projects/Py/test.txt
# check aith os.path
>>> os.path.exists(a.name)
True
注意:
我们还可以使用 filedialog.askopenfilename()
,其中 returns 只是文件的地址 select,这样您就不必担心文件处理程序及其属性。
我们已经有了目的地 folder_dir
和一个新的文件名。
这就是我们所需要的,一个来源和目的地。
这是复制文件的方法
这三种方法的作用相同。根据需要使用其中任何一个。
import os
import shutil
os.rename("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
os.replace("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
请注意,您必须在源参数和目标参数中都包含文件名 (file.foo)。如果更改,文件将被重命名和移动。
另请注意,在前两种情况下,创建新文件的目录必须已经存在。在 Windows 机器上,不能存在具有该名称的文件,否则将引发 exception
,但 os.replace()
即使在这种情况下也会自动替换文件。
您的代码已修改
# Creating object from filedialog
picture = filedialog.askopenfile(mode='r', title='Select activity picture', defaultextension=".jpg")
# Check if cancelled
if picture is None:
return
else:
folder_dir = 'main/data/activity_pics'
pic_name = 'rocket_league' #change to desc_to_img_name() later
path = os.path.join(folder_dir, f'{pic_name}')
# Making the folder if it does not exist yet
if not os.path.exists(folder_dir):
os.makedirs(folder_dir)
# the change here
shutil.move(picture.name, path) # using attribute to get abs address
# Check if successful
if os.path.exists(path):
print(f'File saved as {pic_name} in directory {folder_dir}')
self.picture_path = path
此代码块的缩进不是很好,因为原始问题格式没有缩进那么好。
感谢 Bryan 指出错误 :)