1
1
import locale
2
2
import os
3
+ import pathlib
3
4
import warnings
4
5
from typing import Optional , Union
5
6
6
7
from PySide6 .QtCore import QFile , QIODevice
7
8
8
9
9
- class OpenQFile :
10
+ class QtFileOpen :
10
11
"""
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())
13
19
"""
14
20
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
+ ):
18
27
"""
19
28
:param file: 文件路径
20
29
:param mode: 打开模式(暂时只支持文本读取)
21
30
:param encoding: 文本文件编码
22
31
"""
23
32
33
+ # 预处理文件路径,防止在 Windows 平台下 QFile 只能处理 '/' 导致的问题
34
+ file_path = self .deal_path (file )
35
+ print (file_path )
36
+
24
37
# 分析模式是否合法、返回正确的 FileIo 类实例
25
38
# https://docs.python.org/zh-cn/3/library/functions.html#open
26
39
if "b" not in mode :
27
40
# 文本模式
28
- self .io_obj = PyQTextFileIo (file , mode , encoding )
41
+ self .io_obj = PyQTextFileIo (file_path , mode , encoding )
29
42
else :
30
43
# 二进制模式(暂不支持)
31
44
# self.io_obj = PyQByteFileIo(file, mode)
@@ -37,13 +50,44 @@ def __enter__(self):
37
50
def __exit__ (self , exc_type , exc_val , exc_tb ):
38
51
self .io_obj .close ()
39
52
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
+
40
67
41
68
class PyQTextFileIo :
42
69
"""
43
70
将 QFile 中处理文本文件读写的部分封装成 Python的 io 风格
44
71
目前只支持读取,不支持写入
45
72
"""
46
73
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
+
47
91
@classmethod
48
92
def _parse_mode (cls , py_mode : str ) -> QIODevice :
49
93
"""
@@ -68,26 +112,12 @@ def _parse_mode(cls, py_mode: str) -> QIODevice:
68
112
69
113
return qt_mode
70
114
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
-
86
115
def readable (self ) -> bool :
87
116
"""
88
117
当前文件是否可读 \n
89
118
:return: isReadable
90
119
"""
120
+
91
121
return self ._file .isReadable ()
92
122
93
123
def read (self , size : int = - 1 ) -> str :
@@ -112,7 +142,7 @@ def read(self, size: int = -1) -> str:
112
142
113
143
return text
114
144
115
- def readline (self , size : int = - 1 , / ) -> str :
145
+ def readline (self , size : int = - 1 , / ) -> str :
116
146
"""
117
147
模仿 io.TextIOBase.readline 的行为,读取文件中的一行。 \n
118
148
https://docs.python.org/3/library/io.html#io.TextIOBase.readline
@@ -124,7 +154,9 @@ def readline(self, size: int = - 1, /) -> str:
124
154
raise OSError (f"File '{ self ._file .fileName ()} ' is not Readable." )
125
155
126
156
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
+ )
128
160
return ""
129
161
else :
130
162
if size == 0 :
@@ -161,23 +193,9 @@ def readlines(self, hint: int = -1, /) -> list[str]:
161
193
162
194
return all_lines
163
195
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
+ """
182
200
183
- # f.read() # 离开 with 语句块后文件已经被关闭,无法再读
201
+ self . _file . close ()
0 commit comments