11import locale
22import os
3+ import pathlib
34import warnings
45from typing import Optional , Union
56
67from PySide6 .QtCore import QFile , QIODevice
78
89
9- class OpenQFile :
10+ class QtFileOpen :
1011 """
11- 用于以QFile形式打开文件的上下文管理器 \n
12- 使支持 Python 的 with 风格 \n
12+ 通过 QFile 读写文件的上下文管理器 \n
13+ 使与 Python 的 with 语句风格统一 \n
14+
15+ 使用举例:
16+
17+ with QtFileOpen("./test.txt", "rt", encoding="utf-8") as f:
18+ print(f.read())
1319 """
1420
15- def __init__ (self , file : Union [str , bytes , os .PathLike [str ]],
16- mode = "r" ,
17- encoding : Optional [str ] = None ):
21+ def __init__ (
22+ self ,
23+ file : Union [str , bytes , os .PathLike [str ]],
24+ mode = "r" ,
25+ encoding : Optional [str ] = None ,
26+ ):
1827 """
1928 :param file: 文件路径
2029 :param mode: 打开模式(暂时只支持文本读取)
2130 :param encoding: 文本文件编码
2231 """
2332
33+ # 预处理文件路径,防止在 Windows 平台下 QFile 只能处理 '/' 导致的问题
34+ file_path = self .deal_path (file )
35+ print (file_path )
36+
2437 # 分析模式是否合法、返回正确的 FileIo 类实例
2538 # https://docs.python.org/zh-cn/3/library/functions.html#open
2639 if "b" not in mode :
2740 # 文本模式
28- self .io_obj = PyQTextFileIo (file , mode , encoding )
41+ self .io_obj = PyQTextFileIo (file_path , mode , encoding )
2942 else :
3043 # 二进制模式(暂不支持)
3144 # self.io_obj = PyQByteFileIo(file, mode)
@@ -37,13 +50,44 @@ def __enter__(self):
3750 def __exit__ (self , exc_type , exc_val , exc_tb ):
3851 self .io_obj .close ()
3952
53+ @classmethod
54+ def deal_path (cls , path ) -> str :
55+ """
56+ 预处理文件路径,确保使用 / 风格
57+ :param path: 文件路径
58+ :return: 使用正斜杠(/)的路径字符串
59+ """
60+
61+ # 若路径以字节串传入,则先处理成字符串
62+ if isinstance (path , bytes ):
63+ path = str (path , encoding = locale .getencoding ())
64+
65+ return str (pathlib .PurePath (path ).as_posix ())
66+
4067
4168class PyQTextFileIo :
4269 """
4370 将 QFile 中处理文本文件读写的部分封装成 Python的 io 风格
4471 目前只支持读取,不支持写入
4572 """
4673
74+ def __init__ (
75+ self ,
76+ file : Union [str , bytes , os .PathLike [str ]],
77+ mode ,
78+ encoding : Optional [str ] = None ,
79+ ):
80+ self ._file = QFile (file )
81+
82+ if encoding is not None :
83+ self .encoding = encoding
84+ else :
85+ # 用户未指定编码,则使用当前平台默认编码
86+ self .encoding = locale .getencoding ()
87+
88+ self .mode = self ._parse_mode (mode )
89+ self ._file .open (self .mode )
90+
4791 @classmethod
4892 def _parse_mode (cls , py_mode : str ) -> QIODevice :
4993 """
@@ -68,26 +112,12 @@ def _parse_mode(cls, py_mode: str) -> QIODevice:
68112
69113 return qt_mode
70114
71- def __init__ (self , file : Union [str , bytes , os .PathLike [str ]],
72- mode ,
73- encoding : Optional [str ] = None ):
74-
75- self ._file = QFile (file ) # TODO 处理 QFile 只接受`/`风格路径可能导致 Windows 平台异常的问题
76-
77- if encoding is not None :
78- self .encoding = encoding
79- else :
80- # 用户未指定编码,则使用当前平台默认编码
81- self .encoding = locale .getencoding ()
82-
83- self .mode = self ._parse_mode (mode )
84- self ._file .open (self .mode )
85-
86115 def readable (self ) -> bool :
87116 """
88117 当前文件是否可读 \n
89118 :return: isReadable
90119 """
120+
91121 return self ._file .isReadable ()
92122
93123 def read (self , size : int = - 1 ) -> str :
@@ -112,7 +142,7 @@ def read(self, size: int = -1) -> str:
112142
113143 return text
114144
115- def readline (self , size : int = - 1 , / ) -> str :
145+ def readline (self , size : int = - 1 , / ) -> str :
116146 """
117147 模仿 io.TextIOBase.readline 的行为,读取文件中的一行。 \n
118148 https://docs.python.org/3/library/io.html#io.TextIOBase.readline
@@ -124,7 +154,9 @@ def readline(self, size: int = - 1, /) -> str:
124154 raise OSError (f"File '{ self ._file .fileName ()} ' is not Readable." )
125155
126156 if self ._file .atEnd ():
127- warnings .warn (f"Trying to read a line at the end of the file '{ self ._file .fileName ()} '." )
157+ warnings .warn (
158+ f"Trying to read a line at the end of the file '{ self ._file .fileName ()} '."
159+ )
128160 return ""
129161 else :
130162 if size == 0 :
@@ -161,23 +193,9 @@ def readlines(self, hint: int = -1, /) -> list[str]:
161193
162194 return all_lines
163195
164- def close (self ):
165- self ._file .close ()
166-
167-
168- if __name__ == "__main__" :
169- with OpenQFile (b"./test.txt" , "rt" , encoding = "gbk" ) as f :
170- print (f .read (11 ))
171- # print(f.readline())
172- # lines = f.readlines()
173- # print(lines)
174-
175- print ("-----------" )
176-
177- with open ("./test.txt" , "rt" , encoding = "gbk" ) as f :
178- print (f .read (11 ))
179- # print(f.readline())
180- # lines = f.readlines()
181- # print(lines)
196+ def close (self ) -> None :
197+ """
198+ 关闭打开的文件对象
199+ """
182200
183- # f.read() # 离开 with 语句块后文件已经被关闭,无法再读
201+ self . _file . close ()
0 commit comments