9.5 기존 파일 열기

1. 목표
더보기
파일 메뉴의 Open 액션을 눌렀을 때
- 파일 선택 대화상자에서 텍스트 파일을 선택하고
- QFile, QIODevice, QTextStream 으로 파일 내용을 읽어
- QTextEdit 에 표시한다.
- 파일을 연 뒤에는 current_file 멤버에 경로를 저장하고
문서 수정 여부 플래그를 초기화한다.
2. 전체 로직
더보기
# mainwindow.py
from PySide6.QtWidgets import QMainWindow, QFileDialog, QMessageBox
from PySide6.QtCore import QFile, QIODevice, QDir, QTextStream, QFileInfo
from ui_form import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.current_file = ''
self.editor = self.ui.textEdit
self.ui.actionSave.triggered.connect(self.save_file)
self.ui.actionNew.triggered.connect(self.file_new)
self.ui.actionOpen.triggered.connect(self.open_file)
def file_new(self):
if not self.maybe_save():
return
self.ui.textEdit.clear()
self.current_file = ''
self.ui.textEdit.document().setModified(False)
self.setWindowTitle('제목 없음 - 메모장')
def maybe_save(self) -> bool:
if not self.ui.textEdit.document().isModified():
return True
ret = QMessageBox.warning(
self,
'문서 저장',
'문서가 수정되었습니다.\n변경 내용을 저장하시겠습니까',
QMessageBox.StandardButton.Save
| QMessageBox.StandardButton.Discard
| QMessageBox.StandardButton.Cancel
)
if ret == QMessageBox.StandardButton.Save:
return self.save_file()
if ret == QMessageBox.StandardButton.Cancel:
return False
return True
def save_file(self) -> bool:
filename, _ = QFileDialog.getSaveFileName(
self,
'파일 저장',
QDir.homePath(),
'Text Files (*.txt);;All Files (*)'
)
if not filename:
return False
file = QFile(filename)
if not file.open(QIODevice.WriteOnly | QIODevice.Text):
QMessageBox.critical(self, '오류', f'파일을 열 수 없습니다:\n{file.errorString()}')
return False
stream = QTextStream(file)
stream << self.ui.textEdit.toPlainText()
file.close()
self.current_file = filename
QMessageBox.information(self, '저장 성공', f'파일이 저장되었습니다.\n\n{filename}')
return True
def open_file(self):
filename, _ = QFileDialog.getOpenFileName(
self,
'파일 열기',
QDir.homePath(),
'Text Files (*.txt);;All Files (*)'
)
if not filename:
return
file = QFile(filename)
if not file.open(QIODevice.ReadOnly | QIODevice.Text):
QMessageBox.critical(self, '오류', file.errorString())
return
stream = QTextStream(file)
text = stream.readAll()
file.close()
self.editor.setPlainText(text)
self.current_file = filename
self.editor.document().setModified(False)
info = QFileInfo(filename)
self.setWindowTitle(f'{info.fileName()} - 메모장')
# main.py
import sys
from PySide6.QtWidgets import QApplication
from mainwindow import MainWindow
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec())
3. 필요한 import + 주석 설명
더보기
# QFileInfo
# 파일 이름, 확장자, 경로 등 파일 정보를 얻을 때 사용한다
# 여기서는 창 제목에 파일 이름만 표시하기 위해 사용한다
from PySide6.QtCore import QFileInfo
4. 메뉴 액션과 슬롯 연결하기 ( actionOpen ↔ open_file )
더보기
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.current_file = ''
# 9.5 QTextEdit 를 자주 쓰므로 별칭을 하나 만들어 둔다
self.editor = self.ui.textEdit
self.ui.actionSave.triggered.connect(self.save_file)
self.ui.actionNew.triggered.connect(self.file_new)
# 9.5 기존 파일 열기 기능
# File 메뉴의 Open 액션을 open_file 슬롯에 연결한다
self.ui.actionOpen.triggered.connect(self.open_file)
메뉴 클릭, 툴바 아이콘 클릭, 단축키 Ctrl+O 가
모두 open_file 메서드를 호출하게 됩니다.
5. 실제 기존 파일 열기 기능 구현 함수
더보기
def open_file(self):
'''
9.5 기존 파일 열기 기능
파일 선택 대화상자로 경로를 고르고
Qt 의 QFile, QTextStream 을 이용해 텍스트 파일을 읽어 온 뒤
QTextEdit 에 표시한다
'''
# 1 사용자에게 열 파일을 선택하도록 파일 열기 대화상자를 띄운다
# QDir.homePath 를 초기 경로로 사용하면
# 사용자 홈 디렉터리가 기본으로 열린다
filename, _ = QFileDialog.getOpenFileName(
self,
'파일 열기',
QDir.homePath(),
'Text Files (*.txt);;All Files (*)'
)
# 2 사용자가 취소를 누르면 filename 이 빈 문자열이므로
# 아무 것도 하지 않고 함수를 종료한다
if not filename:
return
# 3 QFile 객체를 생성하고
# 읽기 전용 텍스트 모드로 연다
file = QFile(filename)
if not file.open(QIODevice.ReadOnly | QIODevice.Text):
# 파일을 열지 못한 경우
# errorString 으로 Qt 가 제공하는 오류 메시지를 얻을 수 있다
QMessageBox.critical(
self,
'오류',
f'파일을 열 수 없습니다\n\n{file.errorString()}'
)
return
# 4 QTextStream 을 이용해 파일 전체 내용을 읽어 온다
stream = QTextStream(file)
text = stream.readAll()
# 5 작업이 끝났으므로 파일을 닫는다
file.close()
# 6 QTextEdit 에 읽어 온 내용을 표시한다
# setPlainText 를 사용하면 이전 내용이 모두 교체된다
self.editor.setPlainText(text)
# 7 현재 파일 경로를 멤버 변수에 저장해 둔다
# 이후 다른 기능에서 이 경로를 재사용할 수 있다
self.current_file = filename
# 8 방금 디스크에서 읽어 온 내용이므로
# 수정되지 않은 상태로 표시하기 위해 modified 플래그를 초기화한다
self.editor.document().setModified(False)
# 9 선택 사항
# 창 제목에 파일 이름을 표시하면 사용자가 현재 어떤 파일을 열어 둔 것인지 알기 쉽다
info = QFileInfo(filename)
self.setWindowTitle(f'{info.fileName()} - 메모장')
6. 실행
7.학습 주요 포인트
더보기
1 Qt 형식 파일 열기 흐름 익히기
- QFileDialog getOpenFileName 으로 파일 경로 선택
- QFile 로 파일 객체 생성
- QIODevice ReadOnly Text 플래그로 open 호출
- QTextStream 으로 readAll 호출 후 파일 닫기
- QTextEdit 에 setPlainText 로 반영
2 파이썬 open 과 Qt QFile 차이
- open 은 파이썬 표준 라이브러리
- QFile 은 QIODevice 기반이어서
나중에 네트워크, 메모리 버퍼, 리소스 파일 등
모든 Qt 입출력과 같은 패턴으로 사용할 수 있다. - 교육 과정에서 Qt 파일 입출력 패턴을 익혀 두면
다른 Qt 장치들로도 자연스럽게 확장할 수 있다.
3 QIODevice 플래그 의미
- ReadOnly 읽기 전용
- WriteOnly 쓰기 전용
- Text 텍스트 모드로 열기
윈도우에서 줄바꿈 변환 등 텍스트 처리에 맞게 동작한다.
4 QTextStream 의 장점
- readAll 로 파일 전체를 한 번에 읽을 수 있다.
- operator << 로 텍스트를 쉽게 쓸 수 있다.
- 내부적으로 유니코드 처리와 인코딩을 관리해 주므로
문자열 입출력을 편리하게 다룰 수 있다.
5 current_file 와 문서 상태 관리
- 파일을 열었으면 current_file 에 경로를 보관해 두어야
이후 저장 기능에서 같은 파일로 덮어쓰기 하는 기능을 구현하기 쉽다. - 파일을 방금 열었거나 저장했을 때는
document setModified False 로 수정 없음 상태를 명시적으로 설정해 주는 것이 좋다.
6 [9.3] [9.4] [9.5] 의 연결 구조
- 9 3 파일 저장하기
Qt 파일 쓰기 패턴을 익힌다. - 9 4 새 파일 열기
수정 여부를 확인하고 에디터를 초기화하는 패턴을 익힌다. - 9 5 기존 파일 열기
Qt 파일 읽기 패턴과 current_file, modified 플래그 관리까지 연결한다.
단계별 완성 파일


