试图要求输入文件并将其保存在特定位置

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_dirpath 之后,您想要 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 指出错误 :)