File Operations trong Flet
Học cách làm việc với files: chọn file, đọc/ghi, và upload. ⏱️ 20 phút
🎯 Mục tiêu
Nắm vững:
- FilePicker - Chọn files
- Đọc và ghi files
- Upload files
- Directory picker
📂 FilePicker với Declarative UI
import flet as ft
@ft.observable
class FileState:
selected_files: str = ""
def set_files(self, files_text: str):
self.selected_files = files_text
state = FileState()
@ft.component
def FilePickerDemo(file_picker: ft.FilePicker):
return ft.Column([
ft.ElevatedButton(
"Pick files",
icon=ft.Icons.UPLOAD_FILE,
on_click=lambda _: file_picker.pick_files(allow_multiple=True),
),
ft.Text(state.selected_files or "No files selected"),
], spacing=20)
def main(page: ft.Page):
page.title = "File Picker"
def pick_files_result(e: ft.FilePickerResultEvent):
if e.files:
state.set_files(", ".join([f.name for f in e.files]))
else:
state.set_files("Cancelled")
file_picker = ft.FilePicker(on_result=pick_files_result)
page.overlay.append(file_picker)
page.add(FilePickerDemo(file_picker))
ft.run(main)🔍 Lọc theo loại file
import flet as ft
@ft.observable
class ImagePickerState:
selected_image: str = ""
image_name: str = ""
state = ImagePickerState()
@ft.component
def ImagePickerDemo(file_picker: ft.FilePicker):
return ft.Column([
ft.Container(
content=ft.Image(src=state.selected_image, fit=ft.ImageFit.CONTAIN)
if state.selected_image else ft.Text("No image"),
width=300,
height=300,
bgcolor=ft.Colors.GREY_200,
alignment=ft.alignment.center,
border_radius=10,
),
ft.Text(state.image_name) if state.image_name else None,
ft.ElevatedButton(
"Choose image",
icon=ft.Icons.IMAGE,
on_click=lambda _: file_picker.pick_files(
allowed_extensions=["png", "jpg", "jpeg", "gif"]
),
),
], spacing=15, horizontal_alignment=ft.CrossAxisAlignment.CENTER)
def main(page: ft.Page):
page.title = "Image Picker"
def pick_image(e: ft.FilePickerResultEvent):
if e.files:
state.selected_image = e.files[0].path
state.image_name = e.files[0].name
file_picker = ft.FilePicker(on_result=pick_image)
page.overlay.append(file_picker)
page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.add(ImagePickerDemo(file_picker))
ft.run(main)📖 Đọc nội dung file
import flet as ft
@ft.observable
class TextFileState:
content: str = ""
file_name: str = ""
error: str = ""
def set_content(self, name: str, content: str):
self.file_name = name
self.content = content
self.error = ""
def set_error(self, error: str):
self.error = error
self.content = ""
self.file_name = ""
state = TextFileState()
@ft.component
def TextFileReader(file_picker: ft.FilePicker):
return ft.Column([
ft.ElevatedButton(
"Open text file",
icon=ft.Icons.FILE_OPEN,
on_click=lambda _: file_picker.pick_files(
allowed_extensions=["txt", "md", "py"]
),
),
ft.Text(state.file_name, weight=ft.FontWeight.BOLD) if state.file_name else None,
ft.Container(
content=ft.Text(state.content, selectable=True) if state.content
else ft.Text(state.error, color=ft.Colors.RED) if state.error
else ft.Text("Select a file to view content", color=ft.Colors.GREY),
bgcolor=ft.Colors.GREY_100,
padding=20,
width=500,
border_radius=10,
),
], spacing=15)
def main(page: ft.Page):
page.title = "Text File Reader"
def pick_result(e: ft.FilePickerResultEvent):
if e.files:
file_path = e.files[0].path
try:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
state.set_content(e.files[0].name, content[:1000]) # First 1000 chars
except Exception as ex:
state.set_error(f"Error: {ex}")
file_picker = ft.FilePicker(on_result=pick_result)
page.overlay.append(file_picker)
page.padding = 30
page.add(TextFileReader(file_picker))
ft.run(main)💾 Lưu file (Save As)
import flet as ft
@ft.observable
class EditorState:
content: str = ""
status: str = ""
def set_content(self, text: str):
self.content = text
def set_status(self, status: str):
self.status = status
state = EditorState()
@ft.component
def TextEditor(file_picker: ft.FilePicker):
return ft.Column([
ft.TextField(
value=state.content,
multiline=True,
min_lines=8,
hint_text="Enter your text here...",
on_change=lambda e: state.set_content(e.control.value),
),
ft.Row([
ft.ElevatedButton(
"Save As",
icon=ft.Icons.SAVE,
on_click=lambda _: file_picker.save_file(
file_name="document.txt",
allowed_extensions=["txt"],
),
),
ft.Text(state.status, color=ft.Colors.GREEN if "Saved" in state.status else ft.Colors.GREY),
]),
], spacing=15, expand=True)
def main(page: ft.Page):
page.title = "Text Editor"
page.padding = 30
def save_result(e: ft.FilePickerResultEvent):
if e.path:
try:
with open(e.path, "w", encoding="utf-8") as f:
f.write(state.content)
state.set_status(f"✅ Saved to: {e.path}")
except Exception as ex:
state.set_status(f"❌ Error: {ex}")
else:
state.set_status("Cancelled")
file_picker = ft.FilePicker(on_result=save_result)
page.overlay.append(file_picker)
page.add(TextEditor(file_picker))
ft.run(main)📁 Chọn thư mục
import flet as ft
@ft.observable
class FolderState:
selected_path: str = ""
state = FolderState()
@ft.component
def FolderPicker(file_picker: ft.FilePicker):
return ft.Column([
ft.ElevatedButton(
"Select Folder",
icon=ft.Icons.FOLDER_OPEN,
on_click=lambda _: file_picker.get_directory_path(),
),
ft.Container(
content=ft.Text(state.selected_path or "No folder selected"),
bgcolor=ft.Colors.GREY_100,
padding=15,
border_radius=8,
width=400,
),
], spacing=15)
def main(page: ft.Page):
page.title = "Folder Picker"
page.padding = 30
def pick_folder(e: ft.FilePickerResultEvent):
if e.path:
state.selected_path = e.path
file_picker = ft.FilePicker(on_result=pick_folder)
page.overlay.append(file_picker)
page.add(FolderPicker(file_picker))
ft.run(main)⬆️ Upload file (Web)
Cho ứng dụng web, sử dụng upload:
import flet as ft
@ft.observable
class UploadState:
is_uploading: bool = False
status: str = ""
progress: float = 0
def start_upload(self):
self.is_uploading = True
self.status = "Uploading..."
self.progress = 0
def update_progress(self, progress: float, file_name: str):
self.progress = progress
if progress >= 1:
self.is_uploading = False
self.status = f"✅ Uploaded: {file_name}"
state = UploadState()
@ft.component
def FileUploader(file_picker: ft.FilePicker):
return ft.Column([
ft.ElevatedButton(
"Upload",
icon=ft.Icons.CLOUD_UPLOAD,
on_click=lambda _: file_picker.pick_files(allow_multiple=True),
),
ft.ProgressRing(visible=state.is_uploading),
ft.ProgressBar(value=state.progress, visible=state.is_uploading),
ft.Text(state.status),
], spacing=15)
def main(page: ft.Page):
page.title = "File Uploader"
page.padding = 30
def upload_files(e: ft.FilePickerResultEvent):
if e.files:
state.start_upload()
for f in e.files:
upload_list = [
ft.FilePickerUploadFile(
f.name,
upload_url=page.get_upload_url(f.name, 600),
)
]
file_picker.upload(upload_list)
def upload_progress(e: ft.FilePickerUploadEvent):
state.update_progress(e.progress, e.file_name)
file_picker = ft.FilePicker(
on_result=upload_files,
on_upload=upload_progress,
)
page.overlay.append(file_picker)
page.add(FileUploader(file_picker))
ft.run(main, upload_dir="uploads")📋 FilePicker Methods
| Method | Description |
|---|---|
pick_files() | Chọn files |
save_file() | Lưu file (Save As) |
get_directory_path() | Chọn thư mục |
upload() | Upload files (web) |
⏭️ Tiếp theo
Tuyệt! Tiếp tục với Async Operations để xử lý bất đồng bộ.
Last updated on