Как написать файловый менеджер на питоне

Время на прочтение
10 мин

Количество просмотров 13K

Всем привет!

Я захотел обобщить свои знания питона и решил написать файловый менеджер для пк.

Внимание!

Это всего лишь игрушка и не более, это не реальная ОС!

Импорт библиотек:

import tkinter
import os
import subprocess
from tkinter import messagebox
from tkinter import simpledialog

Главное меню:

class MainContextMenu(tkinter.Menu):
	''' Контекстное меню для внутренней области директории'''
	def __init__(self, main_window, parent):
		super(MainContextMenu, self).__init__(parent, tearoff = 0)
		self.main_window = main_window
		self.add_command(label="Создать директорию", command = self.create_dir)
		self.add_command(label="Создать файл", command = self.create_file)

	def popup_menu(self, event):
		''' функция для активации контекстного меню'''
		#если активны другие меню - отменяем их
		if self.main_window.file_context_menu:
			self.main_window.file_context_menu.unpost()
		if self.main_window.dir_context_menu:
			self.main_window.dir_context_menu.unpost()
		self.post(event.x_root, event.y_root)

	def create_dir(self):
		''' функция для создания новой директории в текущей'''
		dir_name = simpledialog.askstring("Новая директория", "Введите название новой директории")
		if dir_name:
			command = "mkdir {0}".format(dir_name).split(' ')
			#выполняем команду отдельным процессом
			process = subprocess.Popen(command, cwd=self.main_window.path_text.get(), stdout = subprocess.PIPE, stderr = subprocess.PIPE)
			out, err = process.communicate()
			#при возникновении ошибки выводим сообщение
			if err:
				messagebox.showwarning("Операция невозможна!","Отказано в доступе.")
			self.main_window.refresh_window()


	def create_file(self):
		''' функция для создания нового файла в текущей директории'''
		dir_name = simpledialog.askstring("Новый файл", "Введите название нового файла")
		if dir_name:
			command = "touch {0}".format(dir_name).split(' ')
			#выполняем команду отдельным процессом
			process = subprocess.Popen(command, cwd=self.main_window.path_text.get(), stdout = subprocess.PIPE, stderr = subprocess.PIPE)
			out, err = process.communicate()
			#при возникновении ошибки выводим сообщение
			if err:
				messagebox.showwarning("Операция невозможна!","Отказано в доступе.")
			self.main_window.refresh_window()



	def insert_to_dir(self):
		''' функция для копирования файла или директории в текущую директорию'''
		copy_obj = self.main_window.buff
		to_dir = self.main_window.path_text.get()
		if os.path.isdir(self.main_window.buff):
			#выполняем команду отдельным процессом
			process = subprocess.Popen(['cp', '-r', copy_obj, to_dir], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
			out, err = process.communicate()
			if err:
				messagebox.showwarning("Операция невозможна!", err.decode("utf-8"))
		else:
			#выполняем команду отдельным процессом
			process = subprocess.Popen(['cp', '-n', copy_obj, to_dir], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
			out, err = process.communicate()
			#при возникновении ошибки выводим сообщение
			if err:
				messagebox.showwarning("Операция невозможна!",err.decode("utf-8"))
		self.main_window.refresh_window()

При нажатии на файл должно выводиться контекстное меню:

image

class FileContextMenu(tkinter.Menu):
	def __init__(self, main_window, parent):
		super(FileContextMenu, self).__init__(parent, tearoff = 0)
		self.main_window = main_window
		self.add_command(label="Открыть файл", command = self.open_file)
		self.add_separator()
		self.add_command(label="Копировать", command = self.copy_file)
		self.add_command(label="Переименовать", command = self.rename_file)
		self.add_separator()
		self.add_command(label="Удалить", command = self.delete_file)


	def open_file(self):
		''' функция для открытия файла сторонними программами'''
		ext = self.main_window.take_extention_file(self.main_window.selected_file)
		full_path = self.main_window.path_text.get() + self.main_window.selected_file

		if ext in ['txt', 'py', 'html', 'css', 'js']:
			if 'mousepad' in self.main_window.all_program:
				subprocess.Popen(["mousepad", full_path], start_new_session = True)
			else:
				self.problem_message()
		elif ext == 'pdf':
			if 'evince' in self.main_window.all_program:
				subprocess.run(["evince", full_path], start_new_session = True)
			else:
				self.problem_message()
		elif ext in ['png', 'jpeg', 'jpg', 'gif']:
			if 'ristretto' in self.main_window.all_program:
				subprocess.run(["ristretto", full_path], start_new_session = True)
			else:
				self.problem_message()
		else:
			self.problem_message()

	def problem_message(self):
		messagebox.showwarning("Проблема при открытии файла", 'Прости, но я не могу открыть этот файл')

	def copy_file(self):
		''' функция для копирования файла'''
		#заносим полный путь к файлу в буффер
		self.main_window.buff = self.main_window.path_text.get() + self.main_window.selected_file
		self.main_window.refresh_window()


	def delete_file(self):
		''' функция для удаления выбранного файла'''
		full_path = self.main_window.path_text.get() + self.main_window.selected_file
		#выполняем команду отдельным процессом
		process = subprocess.Popen(['rm', full_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
		output, err = process.communicate()
		#при возникновении ошибки выводим сообщение
		if err:
			messagebox.showwarning("Проблема при удалении файла", 'У Вас нет прав для удаления данного файла')
		self.main_window.refresh_window()

	def rename_file(self):
		''' функция для переименования выбранного файла'''
		new_name = simpledialog.askstring("Переименование файла", "Введите новое название файла")
		if new_name:
			old_file = self.main_window.path_text.get() + self.main_window.selected_file
			new_file = self.main_window.path_text.get() + new_name
			#выполняем команду отдельным процессом
			process = subprocess.Popen(['mv', old_file, new_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			output, err = process.communicate()
			#при возникновении ошибки выводим сообщение
			if err:
				messagebox.showwarning("Проблема при переименовании файла", 'У Вас нет прав для переименования данного файла')
			self.main_window.refresh_window()

	def popup_menu(self, event):
		''' функция для активации контекстного меню'''
		self.post(event.x_root, event.y_root)
		#если активны другие меню - отменяем их
		if self.main_window.main_context_menu:
			self.main_window.main_context_menu.unpost()
		if self.main_window.dir_context_menu:
			self.main_window.dir_context_menu.unpost()
		self.main_window.selected_file = event.widget["text"]

То же самое для директории:

class DirContextMenu(tkinter.Menu):
	def __init__(self, main_window, parent):
		super(DirContextMenu, self).__init__(parent, tearoff = 0)
		self.main_window = main_window
		self.add_command(label="Переименовать", command = self.rename_dir)
		self.add_command(label="Копировать", command = self.copy_dir)
		self.add_separator()
		self.add_command(label="Удалить", command = self.delete_dir)

	def copy_dir(self):
		''' функция для копирования директории'''
		self.main_window.buff = self.main_window.path_text.get() + self.main_window.selected_file
		self.main_window.refresh_window()


	def delete_dir(self):
		''' функция для удаления выбранной директории'''
		full_path = self.main_window.path_text.get() + self.main_window.selected_file
		if os.path.isdir(full_path):
			#выполняем команду отдельным процессом
			process = subprocess.Popen(['rm', '-rf', full_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			output, err = process.communicate()
			#при возникновении ошибки выводим сообщение
			if err:
				messagebox.showwarning("Проблема при удалении директории", 'У Вас нет прав для удаления данной директории')
		self.main_window.refresh_window()

	def rename_dir(self):
		''' функция для переименования выбранной директории'''
		new_name = simpledialog.askstring("Переименование директории", "Введите новое название директории")
		if new_name:
			old_dir = self.main_window.path_text.get() + self.main_window.selected_file
			new_dir = self.main_window.path_text.get() + new_name
			#выполняем команду отдельным процессом
			process = subprocess.Popen(['mv', old_dir, new_dir], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			output, err = process.communicate()
			#при возникновении ошибки выводим сообщение
			if err:
				messagebox.showwarning("Проблема при переименовании директории", 'У Вас нет прав для переименования данной директории')
			self.main_window.refresh_window()

	def popup_menu(self, event):
		''' функция для активации контекстного меню'''
		self.post(event.x_root, event.y_root)
		#если активны другие меню - отменяем их
		if self.main_window.main_context_menu:
			self.main_window.main_context_menu.unpost()
		if self.main_window.file_context_menu:
			self.main_window.file_context_menu.unpost()
		self.main_window.selected_file = event.widget["text"]

Класс основного окна:


class MainWindow():
	''' Класс основного окна'''
	def __init__(self):
		self.root = tkinter.Tk()
		self.root.title("FileManager")
		self.root.resizable(width = False, height = False)
		self.root.geometry('450x300')

		self.hidden_dir = tkinter.IntVar()
		self.buff = None
		self.all_program = os.listdir('C:/')

		self.root.bind('<Button-1>', self.root_click)
		self.root.bind('<FocusOut>', self.root_click)

		#top frame
		self.title_frame = tkinter.Frame(self.root)
		self.title_frame.pack(fill = 'both', expand = True)

		#back button
		self.back_button = tkinter.Button(self.title_frame, text = "..", command = self.parent_dir, width = 1, height = 1)
		self.back_button.pack(side = 'left')

		#path entry
		self.path_text = tkinter.StringVar()
		self.path_text.set('/')
		self.current_path = tkinter.Entry(self.title_frame, textvariable = self.path_text, width = 40, state='readonly')
		self.current_path.pack(side = 'left')

		#button show/hidde hidden dir/file
		self.check_button = tkinter.Checkbutton(self.title_frame, text = "Hidden", font = ("Helvetica", 10), padx = 1, pady = 1, variable = self.hidden_dir, command = self.refresh_window)
		self.check_button.pack(side = 'left')

		#main frame
		self.main_frame = tkinter.Frame(self.root)
		self.main_frame.pack()

		# scroll bar
		self.scrollbar_vert = tkinter.Scrollbar(self.main_frame, orient="vertical")
		self.scrollbar_vert.pack(side = 'right', fill = 'y')

		self.scrollbar_hor = tkinter.Scrollbar(self.main_frame, orient="horizontal")
		self.scrollbar_hor.pack(side = 'bottom', fill = 'x')

		#canvas
		self.canvas = tkinter.Canvas(self.main_frame, borderwidth=0,  bg = 'white')
		self.inner_frame = tkinter.Frame(self.canvas,  bg = 'white')

		#команды для прокрутки
		self.scrollbar_vert["command"] = self.canvas.yview
		self.scrollbar_hor["command"] = self.canvas.xview

		#настройки для canvas
		self.canvas.configure(yscrollcommand=self.scrollbar_vert.set, xscrollcommand = self.scrollbar_hor.set, width=400, heigh=250)

		self.canvas.pack(side='left', fill='both', expand=True)
		self.canvas.create_window((0,0), window=self.inner_frame, anchor="nw")


		#отрисовываем содержимое лиректории
		self.dir_content()


	def root_click(self, event):
		''' функция для обработки события клика в root'''
		#если есть контекстные меню - отменяем
		if self.file_context_menu:
			self.file_context_menu.unpost()
		if self.main_context_menu:
			self.main_context_menu.unpost()
		if self.dir_context_menu:
			self.dir_context_menu.unpost()

	def dir_content(self):
		''' функция для определения содержимого текущей директории'''
		#содержимое в текущей директории
		dir_list = os.listdir(self.path_text.get())
		path = self.path_text.get()

		if not dir_list:
			#общее контекстное меню
			self.main_context_menu = MainContextMenu(self, self.canvas)
			self.canvas.bind('<Button-3>', self.main_context_menu.popup_menu)
			if self.buff:
				self.main_context_menu.add_command(label="Вставить", command = self.main_context_menu.insert_to_dir)
			self.inner_frame.bind('<Button-3>', self.main_context_menu.popup_menu)
			#контекстное меню для файлов
			self.file_context_menu = None
			#контекстное меню для директории
			self.dir_context_menu = None
			return None

		#общее контекстное меню
		self.main_context_menu = MainContextMenu(self, self.canvas)
		self.canvas.bind('<Button-3>', self.main_context_menu.popup_menu)
		if self.buff:
			self.main_context_menu.add_command(label="Вставить", command = self.main_context_menu.insert_to_dir)
		#контекстное меню для файлов
		self.file_context_menu = FileContextMenu(self, self.inner_frame)
		#контекстное меню для директории
		self.dir_context_menu = DirContextMenu(self, self.inner_frame)


		i = 0
		for item in dir_list:

			if os.path.isdir(str(path) + item):
				#обрабатываем директории
				if os.access(str(path) + item, os.R_OK):
					if (not self.hidden_dir.get() and  not item.startswith('.')) or self.hidden_dir.get():
						photo = tkinter.PhotoImage(file ="img/folder.png")

						icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')
						icon.image = photo
						icon.grid(row=i+1, column=0)

						folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white', cursor = 'hand1')
						folder_name.bind("<Button-1>", self.move_to_dir)
						folder_name.bind("<Button-3>", self.dir_context_menu.popup_menu)
						folder_name.grid(row=i+1, column=1, sticky='w')
				else:
					if (not self.hidden_dir.get() and not item.startswith('.')) or self.hidden_dir.get():
						photo = tkinter.PhotoImage(file ="img/folder_access.png")

						icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')
						icon.image = photo
						icon.grid(row=i+1, column=0)

						folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')
						folder_name.bind("<Button-1>", self.move_to_dir)
						folder_name.grid(row=i+1, column=1, sticky='w')

			else:
				#обрабатываем файлы
				if (not self.hidden_dir.get() and not item.startswith('.')) or self.hidden_dir.get():
					ext = self.take_extention_file(item)
					#фото, картинки
					if ext in ['jpeg', 'jpg', 'png', 'gif']:
						photo = tkinter.PhotoImage(file ="img/photo.png")

						icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')
						icon.image = photo
						icon.grid(row=i+1, column=0)

						file_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')
						file_name.grid(row=i+1, column=1, sticky='w')

						file_name.bind("<Button-3>", self.file_context_menu.popup_menu)
					else:
						#другие файлы
						if os.access(str(path) + item, os.R_OK):
							photo = tkinter.PhotoImage(file ="img/file.png")

							icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')
							icon.image = photo
							icon.grid(row=i+1, column=0)

							folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')
							folder_name.grid(row=i+1, column=1, sticky='w')

							folder_name.bind("<Button-3>", self.file_context_menu.popup_menu)

						else:
							photo = tkinter.PhotoImage(file ="img/file_access.png")

							icon = tkinter.Label(self.inner_frame, image=photo,  bg = 'white')
							icon.image = photo
							icon.grid(row=i+1, column=0)

							folder_name = tkinter.Label(self.inner_frame, text=item,  bg = 'white')
							folder_name.grid(row=i+1, column=1, sticky='w')
			i += 1
		#обновляем inner_frame и устанавливаем прокрутку для нового содержимого
		self.inner_frame.update()
		self.canvas.configure(scrollregion=self.canvas.bbox("all"))

	def move_to_dir(self, event):
		''' функция для перехода в выбранную директорию'''
		elem = event.widget
		dir_name = elem["text"]
		fool_path = self.path_text.get() + dir_name
		if os.path.isdir(fool_path) and os.access(fool_path, os.R_OK):
			old_path = self.path_text.get()
			self.path_text.set(old_path + dir_name + '/')
			self.root_click('<Button-1>')
			self.refresh_window()


	def parent_dir(self):
		''' функция для перемещения в родительскую директорию'''
		old_path = [i for i in self.path_text.get().split('/') if i]
		new_path = '/'+'/'.join(old_path[:-1])
		if not new_path:
			new_path = '/'
		if os.path.isdir(new_path):
			if new_path == '/':
				self.path_text.set(new_path)

			else:
				self.path_text.set(new_path + '/')
			self.refresh_window()


	def take_extention_file(self, file_name):
		''' функция для получения расширения файла'''
		ls = file_name.split('.')
		if len(ls)>1:
			return ls[-1]
		else:
			return None

	def refresh_window(self):
		''' функция для обновления текущего отображения директорий/файлов'''
		for widget in self.inner_frame.winfo_children():
				widget.destroy()
		self.dir_content()
		self.canvas.yview_moveto(0)

И наконец, создание окна и запаковка виджетов:

win = MainWindow()
win.root.mainloop()

Файлы, ассеты, бинарники здесь

Буду рад, если вы поделитесь со мной улучшенной версией этой программы!
Пишите: ki1killer@yandex.ru

Python File Explorer Project

Using Python’s Tkinter, OS, and shutil modules, we’ll create a GUI-based File Explorer in this Python project. It’s a beginner-level project, so you’ll need a basic understanding of all the libraries, and you’ll get to use them in real life with this project. Let’s get this party started!

A file manager is a piece of software that allows a user to handle various types of files on a computer. The File Explorer, which is included in all operating systems, is the most prevalent sort of file manager.

Python File Explorer Project is Comprised of the Following Components

The goal is to design a File Manager with a graphical user interface. You’ll need a basic grasp of Tkinter, OS, and shutil libraries to develop this.

Prerequisites for the project

The following libraries will be required to complete this python file explorer project:

1. Tkinter is used to develop the graphical user interface (GUI).

2. Operating System (OS) — To operate on a file and its path.

3. Shutil is a command that allows you to copy or move a file.

Python comes with all of the libraries pre-installed.

Structure of the Project Files

To make this python file explorer project, you’ll need to follow these steps:

1. Importing the required modules is the first step.

2. Defining the functionality of all the buttons as well as the GUI window’s variables.

3. Setting up the window, inserting the components, and closing it.

Source Code for Python File Explorer

from tkinter import *
import tkinter.filedialog as fd
import tkinter.messagebox as mb
import os
import shutil
# Creating the backend functions for python file explorer project
def open_file():
   file = fd.askopenfilename(title='Choose a file of any type', filetypes=[("All files", "*.*")])
   os.startfile(os.path.abspath(file))
def copy_file():
   file_to_copy = fd.askopenfilename(title='Choose a file to copy', filetypes=[("All files", "*.*")])
   dir_to_copy_to = fd.askdirectory(title="In which folder to copy to?")
   try:
       shutil.copy(file_to_copy, dir_to_copy_to)
       mb.showinfo(title='File copied!', message='Your desired file has been copied to your desired location')
   except:
       mb.showerror(title='Error!', message='We were unable to copy your file to the desired location. Please try again')
def delete_file():
   file = fd.askopenfilename(title='Choose a file to delete', filetypes=[("All files", "*.*")])
   os.remove(os.path.abspath(file))
   mb.showinfo(title='File deleted', message='Your desired file has been deleted')
def rename_file():
   file = fd.askopenfilename(title='Choose a file to rename', filetypes=[("All files", "*.*")])
   rename_wn = Toplevel(root)
   rename_wn.title("Rename the file to")
   rename_wn.geometry("250x70"); rename_wn.resizable(0, 0)
   Label(rename_wn, text='What should be the new name of the file?', font=("Times New Roman", 10)).place(x=0, y=0)
   new_name = Entry(rename_wn, width=40, font=("Times New Roman", 10))
   new_name.place(x=0, y=30)
   new_file_name = os.path.join(os.path.dirname(file), new_name.get()+os.path.splitext(file)[1])
   os.rename(file, new_file_name)
   mb.showinfo(title="File Renamed", message='Your desired file has been renamed')
def open_folder():
   folder = fd.askdirectory(title="Select Folder to open")
   os.startfile(folder)
def delete_folder():
   folder_to_delete = fd.askdirectory(title='Choose a folder to delete')
   os.rmdir(folder_to_delete)
   mb.showinfo("Folder Deleted", "Your desired folder has been deleted")
def move_folder():
   folder_to_move = fd.askdirectory(title='Select the folder you want to move')
   mb.showinfo(message='You just selected the folder to move, now please select the desired destination where you want to move the folder to')
   destination = fd.askdirectory(title='Where to move the folder to')
   try:
       shutil.move(folder_to_move, destination)
       mb.showinfo("Folder moved", 'Your desired folder has been moved to the location you wanted')
   except:
       mb.showerror('Error', 'We could not move your folder. Please make sure that the destination exists')
def list_files_in_folder():
   i = 0
   folder = fd.askdirectory(title='Select the folder whose files you want to list')
   files = os.listdir(os.path.abspath(folder))
   list_files_wn = Toplevel(root)
   list_files_wn.title(f'Files in {folder}')
   list_files_wn.geometry('250x250')
   list_files_wn.resizable(0, 0)
   listbox = Listbox(list_files_wn, selectbackground='SteelBlue', font=("Georgia", 10))
   listbox.place(relx=0, rely=0, relheight=1, relwidth=1)
   scrollbar = Scrollbar(listbox, orient=VERTICAL, command=listbox.yview)
   scrollbar.pack(side=RIGHT, fill=Y)
   listbox.config(yscrollcommand=scrollbar.set)
   while i < len(files):
       listbox.insert(END, files[i])
       i += 1
# Defining the variables
title = 'File Manager'
background = 'Yellow'
button_font = ("Times New Roman", 13)
button_background = 'Turquoise'
# Initializing the window
root = Tk()
root.title(title)
root.geometry('250x400')
root.resizable(0, 0)
root.config(bg=background)
# Creating and placing the components in the window
Label(root, text=title, font=("Comic Sans MS", 15), bg=background, wraplength=250).place(x=20, y=0)
Button(root, text='Open a file', width=20, font=button_font, bg=button_background, command=open_file).place(x=30, y=50)
Button(root, text='Copy a file', width=20, font=button_font, bg=button_background, command=copy_file).place(x=30, y=90)
Button(root, text='Rename a file', width=20, font=button_font, bg=button_background, command=rename_file).place(x=30, y=130)
Button(root, text='Delete a file', width=20, font=button_font, bg=button_background, command=delete_file).place(x=30, y=170)
Button(root, text='Open a folder', width=20, font=button_font, bg=button_background, command=open_folder).place(x=30, y=210)
Button(root, text='Delete a folder', width=20, font=button_font, bg=button_background, command=delete_folder).place(x=30, y=250)
Button(root, text='Move a folder', width=20, font=button_font, bg=button_background, command=move_folder).place(x=30, y=290)
Button(root, text='List all files in a folder', width=20, font=button_font, bg=button_background,
      command=list_files_in_folder).place(x=30, y=330)
# Finalizing the window
root.update()
root.mainloop()

Output

file explorer

Summary

Congratulations! Using Python’s Tkinter, OS, and shutil modules, you’ve now constructed your own File Manager project. You may use this project to manage files on your computer by opening, moving, deleting, renaming, or copying them, as well as opening, deleting, renaming, and listing all files in a folder.

Python File Explorer Project

Using Python’s Tkinter, OS, and shutil modules, we’ll create a GUI-based File Explorer in this Python project. It’s a beginner-level project, so you’ll need a basic understanding of all the libraries, and you’ll get to use them in real life with this project. Let’s get this party started!

A file manager is a piece of software that allows a user to handle various types of files on a computer. The File Explorer, which is included in all operating systems, is the most prevalent sort of file manager.

Python File Explorer Project is Comprised of the Following Components

The goal is to design a File Manager with a graphical user interface. You’ll need a basic grasp of Tkinter, OS, and shutil libraries to develop this.

Prerequisites for the project

The following libraries will be required to complete this python file explorer project:

1. Tkinter is used to develop the graphical user interface (GUI).

2. Operating System (OS) — To operate on a file and its path.

3. Shutil is a command that allows you to copy or move a file.

Python comes with all of the libraries pre-installed.

Structure of the Project Files

To make this python file explorer project, you’ll need to follow these steps:

1. Importing the required modules is the first step.

2. Defining the functionality of all the buttons as well as the GUI window’s variables.

3. Setting up the window, inserting the components, and closing it.

Source Code for Python File Explorer

from tkinter import *
import tkinter.filedialog as fd
import tkinter.messagebox as mb
import os
import shutil
# Creating the backend functions for python file explorer project
def open_file():
   file = fd.askopenfilename(title='Choose a file of any type', filetypes=[("All files", "*.*")])
   os.startfile(os.path.abspath(file))
def copy_file():
   file_to_copy = fd.askopenfilename(title='Choose a file to copy', filetypes=[("All files", "*.*")])
   dir_to_copy_to = fd.askdirectory(title="In which folder to copy to?")
   try:
       shutil.copy(file_to_copy, dir_to_copy_to)
       mb.showinfo(title='File copied!', message='Your desired file has been copied to your desired location')
   except:
       mb.showerror(title='Error!', message='We were unable to copy your file to the desired location. Please try again')
def delete_file():
   file = fd.askopenfilename(title='Choose a file to delete', filetypes=[("All files", "*.*")])
   os.remove(os.path.abspath(file))
   mb.showinfo(title='File deleted', message='Your desired file has been deleted')
def rename_file():
   file = fd.askopenfilename(title='Choose a file to rename', filetypes=[("All files", "*.*")])
   rename_wn = Toplevel(root)
   rename_wn.title("Rename the file to")
   rename_wn.geometry("250x70"); rename_wn.resizable(0, 0)
   Label(rename_wn, text='What should be the new name of the file?', font=("Times New Roman", 10)).place(x=0, y=0)
   new_name = Entry(rename_wn, width=40, font=("Times New Roman", 10))
   new_name.place(x=0, y=30)
   new_file_name = os.path.join(os.path.dirname(file), new_name.get()+os.path.splitext(file)[1])
   os.rename(file, new_file_name)
   mb.showinfo(title="File Renamed", message='Your desired file has been renamed')
def open_folder():
   folder = fd.askdirectory(title="Select Folder to open")
   os.startfile(folder)
def delete_folder():
   folder_to_delete = fd.askdirectory(title='Choose a folder to delete')
   os.rmdir(folder_to_delete)
   mb.showinfo("Folder Deleted", "Your desired folder has been deleted")
def move_folder():
   folder_to_move = fd.askdirectory(title='Select the folder you want to move')
   mb.showinfo(message='You just selected the folder to move, now please select the desired destination where you want to move the folder to')
   destination = fd.askdirectory(title='Where to move the folder to')
   try:
       shutil.move(folder_to_move, destination)
       mb.showinfo("Folder moved", 'Your desired folder has been moved to the location you wanted')
   except:
       mb.showerror('Error', 'We could not move your folder. Please make sure that the destination exists')
def list_files_in_folder():
   i = 0
   folder = fd.askdirectory(title='Select the folder whose files you want to list')
   files = os.listdir(os.path.abspath(folder))
   list_files_wn = Toplevel(root)
   list_files_wn.title(f'Files in {folder}')
   list_files_wn.geometry('250x250')
   list_files_wn.resizable(0, 0)
   listbox = Listbox(list_files_wn, selectbackground='SteelBlue', font=("Georgia", 10))
   listbox.place(relx=0, rely=0, relheight=1, relwidth=1)
   scrollbar = Scrollbar(listbox, orient=VERTICAL, command=listbox.yview)
   scrollbar.pack(side=RIGHT, fill=Y)
   listbox.config(yscrollcommand=scrollbar.set)
   while i < len(files):
       listbox.insert(END, files[i])
       i += 1
# Defining the variables
title = 'File Manager'
background = 'Yellow'
button_font = ("Times New Roman", 13)
button_background = 'Turquoise'
# Initializing the window
root = Tk()
root.title(title)
root.geometry('250x400')
root.resizable(0, 0)
root.config(bg=background)
# Creating and placing the components in the window
Label(root, text=title, font=("Comic Sans MS", 15), bg=background, wraplength=250).place(x=20, y=0)
Button(root, text='Open a file', width=20, font=button_font, bg=button_background, command=open_file).place(x=30, y=50)
Button(root, text='Copy a file', width=20, font=button_font, bg=button_background, command=copy_file).place(x=30, y=90)
Button(root, text='Rename a file', width=20, font=button_font, bg=button_background, command=rename_file).place(x=30, y=130)
Button(root, text='Delete a file', width=20, font=button_font, bg=button_background, command=delete_file).place(x=30, y=170)
Button(root, text='Open a folder', width=20, font=button_font, bg=button_background, command=open_folder).place(x=30, y=210)
Button(root, text='Delete a folder', width=20, font=button_font, bg=button_background, command=delete_folder).place(x=30, y=250)
Button(root, text='Move a folder', width=20, font=button_font, bg=button_background, command=move_folder).place(x=30, y=290)
Button(root, text='List all files in a folder', width=20, font=button_font, bg=button_background,
      command=list_files_in_folder).place(x=30, y=330)
# Finalizing the window
root.update()
root.mainloop()

Output

file explorer

Summary

Congratulations! Using Python’s Tkinter, OS, and shutil modules, you’ve now constructed your own File Manager project. You may use this project to manage files on your computer by opening, moving, deleting, renaming, or copying them, as well as opening, deleting, renaming, and listing all files in a folder.

Лабораторная работа 1. Файловый tменеджер

Цель лабораторной работы:

Научиться создавать сложный проект и научиться программно работать с локальными файлами и папками.

Задания для выполнения:

Необходимо создать примитивный файловый менеджер. Программа должна работать в определенной папке (рабочей папки менеджера) и позволять пользователю выполнять следующие простые действия в пределах рабочей папки:

  1. Создание папки (с указанием имени);

  2. Удаление папки по имени;

  3. Перемещение между папками (в пределах рабочей папки) — заход в папку по имени, выход на уровень вверх;

  4. Создание пустых файлов с указанием имени;

  5. Запись текста в файл;

  6. Просмотр содержимого текстового файла;
     

  7. Удаление файлов по имени;

  8. Копирование файлов из одной папки в другую;
     

  9. Перемещение файлов;

  10. Переименование файлов.

Указания к выполнению

  1. Расположение рабочей папки должно указываться в настройках файлового менеджера. Настройки должны располагаться в отдельном от основного исходного кода файле.

  2. Файловый менеджер должен блокировать пользователя от выхода за пределы рабочей папки. Пользователь должен воспринимать рабочую папку как корневую и все действия файлового менеджера должны локализоваться только в пределах этой папки.

  3. Программный проект должен быть оформлен как код на языке программирования Python и располагаться в определенной папке. Проект должен состоять из нескольких файлов. Расположение рабочей папки не должно быть связано с физическим расположением файлов исходного кода.

  4. Файловый менеджер по умолчанию должен иметь текстовый интерфейс по аналогии с интерфейсом командной строки. Действия пользователя осуществляются вводом с клавиатуры соответствующей команды (по необходимости с параметрами).

  5. Код должен быть организован в виде набора функций или классов, каждая операция файлового менеджера должна быть реализована в отдельной функции или методе класса.

  6. Файловый менеджер должен быть кроссплатформенным и работать как в среде Windows, так и в UNIX системах. Необходимо протестировать работоспособность программы в разных ОС. Для кроссплатформенности рекомендуется использовать стандартную библиотеку Python для осуществления файловых операций.

  7. Разработка программы должна вестись с использованием СКВ Git. Код должен публиковаться в репозитории на GitHub.

  8. Перед разработкой программист должен продумать названия и структуру команд для пользователя. Команды не должны повторять команды существующих программных оболочек.

Дополнительные задания

  1. Сделайте файловый менеджер многопользовательским. Добавьте возможность регистрации пользователей. При регистрации каждому пользователю создается своя домашняя папка, в пределах которой он может работать.

  2. Придумайте и добавьте дополнительные функциональные возможности для файлового менеджера. Сделаем: Квотирование дискового пространства и отображение занятого оставшегося места.

Using Tkinter, to create a file explorer in Python.

Using Python’s Tkinter, OS, and shutil modules, we’ll create a GUI-based File Explorer in this Python project.
It’s a beginner-level project, so you’ll need a basic understanding of all the libraries, and you’ll get to use them in real life with this project. Let’s get this coding started!

About File Managers:

A file manager is a piece of software that allows a user to handle various types of files on a computer.
The File Explorer, which is included in all operating systems, is the most widely recognized sort of file manager.

About the python file explorer project:

The goal is to design a File Manager with a graphical user interface.
You’ll need a basic understanding of Tkinter, OS, and shutil libraries to develop this.

Structure of the Project’s Files

To make this python file explorer project, you’ll need to follow these steps:

  1. Importing the required modules is the first step.
  2.  Defining the functions of all the buttons as well as the GUI window’s variables.
  3. Setting up the window, inserting the components, and closing it.

Project Prerequisites:

The following libraries will be required to complete this python file explorer project:

1. Tkinter is used to develop the graphical user interface (GUI).

2. Operating System (OS) – To operate on a file and its path.

3. Shutil is a command that allows you to copy or move a file.

1. Importing all required modules:

				
					from tkinter import *
import tkinter.filedialog as fd
import tkinter.messagebox as mb
import os
import shutil
				
			

Explanation:

  • The from tkinter import * statement imports everything from the tkinter library’s init file.
  • The filedialog module contains routines for opening and saving dialogues.
  • The messagebox module is a set of functions that show various types of messages using various icons.

2. Defining the functions of all the buttons and the variables for the GUI window:

				
					# Creating the backend functions for python file explorer project
def open_file():
   file = fd.askopenfilename(title='Choose a file of any type', filetypes=[("All files", "*.*")])

   os.startfile(os.path.abspath(file))


def copy_file():
   file_to_copy = fd.askopenfilename(title='Choose a file to copy', filetypes=[("All files", "*.*")])
   dir_to_copy_to = fd.askdirectory(title="In which folder to copy to?")

   try:
       shutil.copy(file_to_copy, dir_to_copy_to)
       mb.showinfo(title='File copied!', message='Your desired file has been copied to your desired location')
   except:
       mb.showerror(title='Error!', message='We were unable to copy your file to the desired location. Please try again')


def delete_file():
   file = fd.askopenfilename(title='Choose a file to delete', filetypes=[("All files", "*.*")])

   os.remove(os.path.abspath(file))

   mb.showinfo(title='File deleted', message='Your desired file has been deleted')


def rename_file():
   file = fd.askopenfilename(title='Choose a file to rename', filetypes=[("All files", "*.*")])

   rename_wn = Toplevel(root)
   rename_wn.title("Rename the file to")
   rename_wn.geometry("250x70"); rename_wn.resizable(0, 0)

   Label(rename_wn, text='What should be the new name of the file?', font=("Times New Roman", 10)).place(x=0, y=0)

   new_name = Entry(rename_wn, width=40, font=("Times New Roman", 10))
   new_name.place(x=0, y=30)

   new_file_name = os.path.join(os.path.dirname(file), new_name.get()+os.path.splitext(file)[1])

   os.rename(file, new_file_name)
   mb.showinfo(title="File Renamed", message='Your desired file has been renamed')


def open_folder():
   folder = fd.askdirectory(title="Select Folder to open")
   os.startfile(folder)


def delete_folder():
   folder_to_delete = fd.askdirectory(title='Choose a folder to delete')
   os.rmdir(folder_to_delete)
   mb.showinfo("Folder Deleted", "Your desired folder has been deleted")


def move_folder():
   folder_to_move = fd.askdirectory(title='Select the folder you want to move')
   mb.showinfo(message='You just selected the folder to move, now please select the desired destination where you want to move the folder to')
   destination = fd.askdirectory(title='Where to move the folder to')

   try:
       shutil.move(folder_to_move, destination)
       mb.showinfo("Folder moved", 'Your desired folder has been moved to the location you wanted')
   except:
       mb.showerror('Error', 'We could not move your folder. Please make sure that the destination exists')


def list_files_in_folder():
   i = 0

   folder = fd.askdirectory(title='Select the folder whose files you want to list')

   files = os.listdir(os.path.abspath(folder))

   list_files_wn = Toplevel(root)
   list_files_wn.title(f'Files in {folder}')
   list_files_wn.geometry('250x250')
   list_files_wn.resizable(0, 0)

   listbox = Listbox(list_files_wn, selectbackground='SteelBlue', font=("Georgia", 10))
   listbox.place(relx=0, rely=0, relheight=1, relwidth=1)

   scrollbar = Scrollbar(listbox, orient=VERTICAL, command=listbox.yview)
   scrollbar.pack(side=RIGHT, fill=Y)

   listbox.config(yscrollcommand=scrollbar.set)

   while i < len(files):
       listbox.insert(END, files[i])
       i += 1


# Defining the variables
title = 'IAMNK File Manager'
background = '#C80D0D'

button_font = ("Times New Roman", 13)
button_background = '#ffde59'
				
			

Explanation:

  • The components of the filedialog module utilised in this project are as follows:
    • To pick a file, use the askfilename function, with title title and filetypes filetypes.
    • To choose a folder, use the askdirectory function.
    • Both of these functions keep track of the file’s path.
  • The components of the OS library utilised in this project are as follows:
    • The path module has the following functions:
        • The abspath function returns the path of the file sent in as an argument.
      • The join function joins two portions of a file, usually the name and extension.
      • The dirname function returns the name of the directory in which a file is stored.
      • The splittext function is used to split a file’s name into a list with the file’s name and extensions as separate items.
  • The init module has the following functions:
      • To rename a file or folder, use the rename function.
      • To open a file in an external application, use the startfile function.
      • To delete a whole directory, use the rmdir function.
      • To delete a file, use the remove function.
  • The following are the components of the Shutil library that were utilised in this project:
    • The copy function copies a file from its source location, src, to the computer’s desired destination, dst.
    • The move function is used to move a file from one location to another, from source to destination.

Note: In the next step, all of the tkinter aspects in this step will be described.

3. Creating the window, putting the components in place, and finishing it:

				
					# Initializing the window
root = Tk()
root.title(title)
root.geometry('250x400')
root.resizable(0, 0)
root.config(bg=background)

# Creating and placing the components in the window
Label(root, text=title, font=("Comic Sans MS", 15), bg=background, wraplength=250).place(x=20, y=0)

Button(root, text='Open a file', width=20, font=button_font, bg=button_background, command=open_file).place(x=30, y=50)

Button(root, text='Copy a file', width=20, font=button_font, bg=button_background, command=copy_file).place(x=30, y=90)

Button(root, text='Rename a file', width=20, font=button_font, bg=button_background, command=rename_file).place(x=30, y=130)

Button(root, text='Delete a file', width=20, font=button_font, bg=button_background, command=delete_file).place(x=30, y=170)

Button(root, text='Open a folder', width=20, font=button_font, bg=button_background, command=open_folder).place(x=30, y=210)

Button(root, text='Delete a folder', width=20, font=button_font, bg=button_background, command=delete_folder).place(x=30, y=250)

Button(root, text='Move a folder', width=20, font=button_font, bg=button_background, command=move_folder).place(x=30, y=290)

Button(root, text='List all files in a folder', width=20, font=button_font, bg=button_background,
      command=list_files_in_folder).place(x=30, y=330)

# Finalizing the window
root.update()
root.mainloop()
				
			

Explanation:

  • The GUI window is assigned to a variable using the Tk() class.
    • The.title() method is used to give the window a title.
    • The.geometry() method is used to define the window’s initial geometry.
    • The.resizable() method is used to give the user the option of resizing or not resizing a window.
    • The.config() method is used to configure the object’s extra characteristics.
  • The Label class creates a Label widget in the window, which is a frame for displaying static text. It has the following methods and attributes:
      • The widget’s parent window is specified by the master attribute.
    • The text attribute is used to specify the text that will be shown in the widget.
    • The font element is used to provide the text’s font name, font size, and bold/italic.
    • The bg attribute specifies the widget’s background colour.
    • The wraplength property specifies how many pixels the text will wrap to next line after.
  • The Button class adds a button to its parent element that, when pressed, performs a function.
    It has the following characteristics:
    • The widget’s width attribute specifies the widget’s length in pixels.
    • When the button is pressed, the command attribute is used to specify the function that will be performed.
    • The other characteristics have already been mentioned.
  • The Toplevel class is similar to the Frame widget, except that its child widgets are always displayed in a new window.
    • This class has the same methods and characteristics as the Tk() class.
  • In the GUI window, the Entry class is used to add an input field.
    It employs the following strategies:
    • The textvariable property is used to create a StringVar(string), IntVar(integer), or DoubleVar(float) variable to store or update the value in the Entry widget, as well as to give it a type [as shown in brackets against the __Var words].
    • The class’s other characteristics have already been explored.
    • The.get() method is used to retrieve the user’s input.
      This method does not accept any parameters.
  • The Listbox class is used to add a multiline, static textbox to the window from which the user can choose items.
    • The selectbackground attribute is used to define the colour of the selected background.
    • The yscroll command attribute is used to specify the scrollbar that will be used to manage the widget’s up-and-down scrolling.
    • The other characteristics have already been mentioned.
    • To insert an element or elements, *elements, at the index index, use the.insert(index, *elements) method.
    • An appropriate tkinter constant or an integer can be used as the index argument.
    • The.yview() method is used to create a scrollbar that allows you to see the up and down of the widget you’re working with.
  • The Scrollbar class is used to add a scrollbar to a widget’s parent that regulates the parent’s movement.
    • The orient parameter specifies the orientation of the scrollbar on the window.
    • The other characteristics have already been mentioned.
    • To connect the scrollbar to another widget, use the.set() method.

The Complete Code:

				
					from tkinter import *
import tkinter.filedialog as fd
import tkinter.messagebox as mb

import os
import shutil

# Creating the backend functions
def open_file():
    file = fd.askopenfilename(title='Choose a file of any type', filetypes=[("All files", "*.*")])

    os.startfile(os.path.abspath(file))


def copy_file():
    file_to_copy = fd.askopenfilename(title='Choose a file to copy', filetypes=[("All files", "*.*")])
    dir_to_copy_to = fd.askdirectory(title="In which folder to copy to?")

    try:
        shutil.copy(file_to_copy, dir_to_copy_to)
        mb.showinfo(title='File copied!', message='Your desired file has been copied to your desired location')
    except:
        mb.showerror(title='Error!', message='We were unable to copy your file to the desired location. Please try again')


def delete_file():
    file = fd.askopenfilename(title='Choose a file to delete', filetypes=[("All files", "*.*")])

    os.remove(os.path.abspath(file))

    mb.showinfo(title='File deleted', message='Your desired file has been deleted')


def rename_file():
    file = fd.askopenfilename(title='Choose a file to rename', filetypes=[("All files", "*.*")])

    rename_wn = Toplevel(root)
    rename_wn.title("Rename the file to")
    rename_wn.geometry("250x70"); rename_wn.resizable(0, 0)

    Label(rename_wn, text='What should be the new name of the file?', font=("Times New Roman", 10)).place(x=0, y=0)

    new_name = Entry(rename_wn, width=40, font=("Times New Roman", 10))
    new_name.place(x=0, y=30)

    new_file_name = os.path.join(os.path.dirname(file), new_name.get()+os.path.splitext(file)[1])

    os.rename(file, new_file_name)
    mb.showinfo(title="File Renamed", message='Your desired file has been renamed')


def open_folder():
    folder = fd.askdirectory(title="Select Folder to open")
    os.startfile(folder)


def delete_folder():
    folder_to_delete = fd.askdirectory(title='Choose a folder to delete')
    os.rmdir(folder_to_delete)
    mb.showinfo("Folder Deleted", "Your desired folder has been deleted")


def move_folder():
    folder_to_move = fd.askdirectory(title='Select the folder you want to move')
    mb.showinfo(message='You just selected the folder to move, now please select the desired destination where you want to move the folder to')
    destination = fd.askdirectory(title='Where to move the folder to')

    try:
        shutil.move(folder_to_move, destination)
        mb.showinfo("Folder moved", 'Your desired folder has been moved to the location you wanted')
    except:
        mb.showerror('Error', 'We could not move your folder. Please make sure that the destination exists')


def list_files_in_folder():
    folder = fd.askdirectory(title='Select the folder whose files you want to list')

    files = os.listdir(str(os.path.abspath(folder)))

    list_files_wn = Toplevel(root)
    list_files_wn.title('Files in your selected folder')
    list_files_wn.geometry('150x250')
    list_files_wn.resizable(0, 0)

    listbox = Listbox(list_files_wn, selectbackground='SteelBlue', font=("Georgia", 10), height=15, width=20)

    scrollbar = Scrollbar(listbox, orient=VERTICAL, command=listbox.yview)
    scrollbar.pack(side=RIGHT)

    listbox.config(yscrollcommand=scrollbar.set)
    listbox.place(x=10, y=10)

    for file in list(files):
        listbox.insert(END, file)


# Defining the variables
title = 'IAMNK File Manager'
background = '#C80D0D'

button_font = ("Times New Roman", 13)
button_background = '#ffde59'

# Initializing the window
root = Tk()
root.title(title)
root.geometry('250x400')
root.resizable(0, 0)
root.config(bg=background)

# Creating and placing the components in the window
Label(root, text=title, font=("Comic Sans MS", 15), bg=background, wraplength=250).place(x=20, y=0)

Button(root, text='Open a file', width=20, font=button_font, bg=button_background, command=open_file).place(x=30, y=50)

Button(root, text='Copy a file', width=20, font=button_font, bg=button_background, command=copy_file).place(x=30, y=90)

Button(root, text='Rename a file', width=20, font=button_font, bg=button_background, command=rename_file).place(x=30, y=130)

Button(root, text='Delete a file', width=20, font=button_font, bg=button_background, command=delete_file).place(x=30, y=170)

Button(root, text='Open a folder', width=20, font=button_font, bg=button_background, command=open_folder).place(x=30, y=210)

Button(root, text='Delete a folder', width=20, font=button_font, bg=button_background, command=delete_folder).place(x=30, y=250)

Button(root, text='Move a folder', width=20, font=button_font, bg=button_background, command=move_folder).place(x=30, y=290)

Button(root, text='List all files in a folder', width=20, font=button_font, bg=button_background,
       command=list_files_in_folder).place(x=30, y=330)

# Finalizing the window
root.update()
root.mainloop()

				
			

The Final Output:

Capture Of File Manager

Here are examples of file managers you can use for inspiration:

  • FreeCommander: An easy-to-use alternative to the standard windows file manager
  • Explorer++: A lightweight and fast file manager for Windows

Here are resources that you can use to build your file manager:

  • os Module: Miscellaneous operating system interfaces
  • sys Module: System-specific parameters and functions
  • shutil Module: High-level file operations
  • re Module: Python3 documentation — Regular expression operations

00:00

File Manager. Most computers will have thousands of files present on them: pictures, videos, text, audio, and other documents. If they’re all placed in a single directory, it would be next to impossible to navigate through and find what you’re after.

00:15

That’s one of the reasons that computers use directories, but we still need to move files and folders around to create some order. File managers are the way to perform this management, allowing users to manage files and directories through a user interface that typically involves a view of the directory structure, as well as files as contained in each directory. Functions such as cut, copy, and paste allow the efficient management of files into their desired structure, and being able to create, delete, and rename files and directories is also necessary. While all of these functions are available to users via the command line, most are not aware of this and will find it difficult to use, so a GUI-based file manager is a much better solution for them for this kind of task.

01:00

Let’s take a look at a couple of file manager implementations for Windows.

01:04

Here, you can see FreeCommander in operation, with two panes open. On the left is the contents of the local C: drive on this particular PC, and on the right, looking in Documents/.

01:18

It’s possible to copy and paste items between. So, for instance, we can copy this file by right-clicking, Copy, and then right-click, and Paste—the kind of file management you’ll be used to operating.

01:31

It’s also possible to view these in different modes. Here, we have list, then details,

01:39

thumbnails, and a toggle button, which takes us between two views. Here, you can see Explorer++ in action with the familiar directory tree on the left, and the contents of the selected directory on the right. It’s possible to select a wide range of views, such as different kinds of icons, a list, details, et cetera,

02:03

and the file manipulations are available via a right-click menu, icons on the toolbar, then the menu here, and also by the familiar keyboard shortcuts.

02:17

Let’s take a look at some of the technical challenges you’ll need to overcome to program your file manager. First—and rather obviously—accessing files. If you’ve programmed these projects in order, you will already have some experience of using these libraries from the previous command-line based projects. Accessing files is, of course, table stakes for a file manager, and these libraries make much of it simple and cross-platform when used appropriately. Secondly, displaying files. You’ll need to decide on a convention for file display. As seen in the examples, it’s possible to have different methods of display—list, icons, details, et cetera—and you’ll need to implement all of this in a manner that allows each item to be selectable from within the user interface. Creation of directories and files.

03:06

Creation of new directories and files is useful, particularly for creating new files with appropriate extensions or metadata to allow them to be edited in the correct application. Copy, cut, and paste.

03:19

You will need to implement these essential functions in a manner which is fail-safe—particularly cut. You don’t want to create a file manager that has a reputation for being a file mangler.

03:31

Now, let’s take a look at some of the extra challenges for the file manager project. First up, search. Many file managers, such as Windows Explorer and the macOS Finder, implement a search function. Adding an advanced search function which uses regular expressions will be a worthwhile challenge.

03:49

Sort. Being able to sort the output of the file manager via filename, file extension, date of creation, or size—whether ascending or descending—is an important addition to our app’s usability.

Может наступить время, когда вам потребуется более тонкое управление файловым объектом, для этого нужно создать собственный контекстный менеджер.

Для чего это нужно? Допустим, может возникнут такая ситуация, когда часто нужно будет открывать файлы .png и анализировать их. И что-бы не разбирать заголовочный файл каждый раз нужно создать узконаправленный менеджер контекста. Вот пример того, как это сделать. Здесь также будем использовать пользовательские итераторы.

У менеджера контекста есть два «магических метода»:

  • __enter__() — вызывается при вызове оператора with.
  • __exit__() вызывается при выходе из блока оператора with.

Вот шаблон, который можно использовать для создания нашего менеджера:

class pngReader():
    def __init__(self, file_path):
        self.__path = file_path
        self.__file_object = None

    def __enter__(self):
        self.__file_object = open(self.__path)
        return self

    def __exit__(self, type, val, tb):
        self.__file_object.close()

После того, как допишем в шаблон выше необходимые методы, мы сможем использовать его аналогично встроенной функции open() :

with pngReader('file.png') as fp:
    # Выполнение пользовательских операций
    pass

Вот код класса контекстного менеджера с комментариями, который читает любой PNG файл:

class pngReader():
    # Формат файла png содержит в заголовке определенный набор символов.  
    # Используем его для проверки, что файл действительно является PNG.
    _expected_magic = b'x89PNGrnx1an'

    def __init__(self, file_path):
        # Убедимся, что файл имеет нужное расширение
        if not file_path.endswith('.png'):
            raise NameError("Файл должен иметь расширение '.png'")
        self.__path = file_path
        self.__file_object = None

    def __enter__(self):
        self.__file_object = open(self.__path, 'rb')
        magic = self.__file_object.read(8)
        # Проверяем первые 8 байт заголовка 
        # на определенный набор символов
        if magic != self._expected_magic:
            raise TypeError("Это не '.png' файл!")
        return self

    def __exit__(self, type, val, tb):
        self.__file_object.close()

    def __iter__(self):
        # Этот метод и следующий __next__() используются
        # для чтения PNG файла кусками
        return self

    def __next__(self):
        # Читаем файл кусками
        initial_data = self.__file_object.read(4)
        # Файл не был открыт или достигнут конец файла.
        if self.__file_object is None or initial_data == b'':
            # Поднимаем исключение StopIteration.
            raise StopIteration
        else:
            # Каждый блок имеет длину, тип, данные (на основе len) и crc
            chunk_len = int.from_bytes(initial_data, byteorder='big')
            chunk_type = self.__file_object.read(4)
            chunk_data = self.__file_object.read(chunk_len)
            chunk_crc = self.__file_object.read(4)
            # вернем их в виде кортежа
            return chunk_len, chunk_type, chunk_data, chunk_crc

Сохраните код в файл pngreader.py и расположите его в корневой директории. Теперь можно открыть любой .png файл и правильно его анализировать:

>>> from pngreader import pngReader
>>> png_file = '/path/to/png/file.png'
>>> with pngReader(png_file) as fp:
...     for ln, tp, dt, crc in fp:
...         print(f"{ln:05}, {tp}, {crc}")
...     
# 00013, b'IHDR', b'xc8xa8x0bxc2'
# 00428, b'zTXt', b'x17Oyxea'
# 00004, b'sBIT', b'|x08dx88'
# 06586, b'IDAT', b'xc0x14xc5R'
# 00000, b'IEND', b'xaeB`x82'

Понравилась статья? Поделить с друзьями:
  • Как написать файл эксель
  • Как написать файл dll
  • Как написать фае или фойе правильно
  • Как написать фабулу
  • Как написать уютный дом английскими буквами