29. 文件操作

一、数据读写

  在程序运行时会生成各种各样的数据,如果数据量少,可以直接将其保存在内存中,计算结束时清空内存并把结果保存到文件中。如果在计算中生成大量的中间数据,则需要把数据写到临时文件中,计算结束时把临时文件删除。

  为保存数据,可以用 Python 提供的 open() 函数 打开或新建文件进行文本文件的读写,对于大量的有固定格式的数据,可以用PySide6 提供的以数据流的方式读写文本数据、二进制数据和原生数据的方法和函数,以及对临时文件进行管理和监控的函数,很方便地对数据进行读写和对文件进行管理。

  在 PySide6 中,我们可以把文件当作输入输出设备,可以把数据写到设备中,或者从设备中读取数据,从而达到读写数据的目的。我们可以利用 QFile 类调用 QIODevice 类的读写方法 直接进行读写,或者把 QFile 类和 QTextStream 类结合起来,用 文本流(text stream)的方法进行文本数据的读写,还可以把 QFile 类和 QDataStream 类结合进来,用 数据流(data stream)的方法进行二进制数据的读写。

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

在 PySide6 窗口程序对文件或者文件夹进行操作时,不强制要求必须使用 PySide6 中提供的 QFileQDir 等类,也可以使用 Python 内置的文件对象。

1.1、QIODevice抽象类

  PySide6 中用于文件读写操作的类是 QFile,它提供了文件读写的接口函数,可以直接对文件进行读写。QFile 的父类是 QFileDevice,它提供了文件交互操作的底层功能。再上一级父类是 QIODevice,它是所有输入/输出设备的基础类。

与文件读写有关的类

  QIODevice 类是抽象类,是执行读数据和写数据类(如 QFileQBuffer)的基类,它提供读数据和写数据的接口。QIODevice 类在 QtCore 模块中。我们不能直接使用 QIODevice 类进行数据的读写,而是使用子类 QFileQBuffer 的继承自 QIODevice 的读写方法来进行数据读写。在一些系统中,将所有的外围设备都当作文件来处理,因此可以读写的类都可以当作设备来处理。

  QIODevice 类的常用方法如下:

open(mode:QIODeviceBase.OpenMode) -> bool                                       # 打开设备,成功返回True
isOpen() -> bool                                                                # 判断设备是否打开
setOpenMode(openMode:QIODeviceBase.OpenMode) -> None                            # 打开设备后,重新设置打开模式
close() -> None                                                                 # 关闭设备   

setTextModeEnabled(enabled:bool) -> None                                        # 设置是否是文本模式

getChar(c:bytes) -> bool                                                        # 读取一个字符,并存储到c中
putChar(c:str) -> bool                                                          # 写入一个字符
ungetChar(c:str) -> None                                                        # 将字符重新存储到设备中

peek(length:int) -> QByteArray                                                  # 读取指定数量的字节

read(length:int) -> QByteArray                                                  # 读取指定数量的字节数据
readLine(length:int) -> QByteArray                                              # 读取一行数据
readData(length:int) -> QObject                                                 # 读取数据
readAll() -> QByteArray                                                         # 读取全部数据

write(data:Union[QByteArray, byteArray]) -> int                                 # 写入字符串,返回实际写入的字节数量
writeData(data:bytes, length:int) -> int                                    # 写入数据,返回实际写入的字节数量 

setCurrentWriteChannel(channel:int) -> None                                     # 设置当前的写入通道
currentWriteChannel() -> int                                                    # 获取当前的写入通道
writeChannelCount() -> int                                                      # 获取写入数据的通道数量

setCurrentReadChannel(channel:int) -> None                                      # 设置当前的读取通道
currentReadChannel() -> int                                                     # 获取当前的读取通道
readChannelCount() -> int                                                       # 获取读取数据的通道数量

canReadLine() -> bool                                                           # 获取是否可以按行读取

bytesToWrite() -> int                                                           # 获取缓存中等待写入的字节数量
bytesAvailable() -> int                                                         # 获取可读取的字节数量

setErrorString(text:str) -> None                                                # 设置设备的出错信息
errorString() -> st                                                             # 获取设备的出错信息

isWritable() -> bool                                                            # 获取设备是否可以写入
isReadable() -> bool                                                            # 获取设备是否可以读取
isSequential() -> bool                                                          # 获取设备是否是顺序读取
isTextModeEnabled() -> bool                                                     # 获取设备是否能够以文本方式读写

atEnd() -> bool                                                                 # 获取是否已经到达文件末尾
seek(posision:int) -> None                                                      # 移动到指定的位置
pos() -> int                                                                    # 获取当前位置
reset() -> bool                                                                 # 重置设备,回到起始位置

startTransaction() -> None                                                      # 对随机设备记录当前位置,对顺序设备,在内部赋值读取的数据以便恢复数据
rollbackTransaction() -> None                                                   # 回到调用startTransaction()时的位置
commitTransaction() -> None                                                     # 对顺序设备,放弃记录的数据
isTransactionStarted() -> bool                                                  # 获取是否开始记录位置

size() -> int                                                                   # 获取文件大小
skip(size:int) -> int                                                           # 跳过指定数量的字节数据

waitForBytesWritten(millisecond:int) -> bool                                    # 对于缓存设备,该方法需要将数据写到设备或进故宫msecs毫秒后返回值
waitForReadyRead(millisecond:int) -> bool                                       # 当有数据可以读取前或经过msecs毫秒会阻止设备的运行

  QIODevice 的子类 QFileQBufferQTcpSocket 等需要用 open(mode:QIODeviceBase.OpenMode) 方法 打开一个设备,用 close() 方法 关闭设备。打开设备时需要 设置打开模式,参数 modeQIODeviceBase.OpenMode 类型的枚举值,可以取值如下所示,可以设置只读、只写、读写、追加和不使用缓存等模式,如果同时要选择多个选项可以用 | 连接:

QIODeviceBase.OpenModeFlag.NotOpen                                              # 还未打开
QIODeviceBase.OpenModeFlag.ReadOnly                                             # 以只读的方式打开
QIODeviceBase.OpenModeFlag.WriteOnly                                            # 以只写的方式打开,如果文件不存在,则创建新文件
QIODeviceBase.OpenModeFlag.ReadWrite                                            # 以读写的方式打开,如果文件不存在,则创建新文件
QIODeviceBase.OpenModeFlag.Append                                               # 以追加的方式打开,新增加的内容将被追加到文件末尾
QIODeviceBase.OpenModeFlag.Truncate                                             # 以重写的方式打开,在写入新的数据是会将原有数据全部清除,指针指向文件开头
QIODeviceBase.OpenModeFlag.Text                                                 # 在读写时,将行结束符转换成\n,在写入时将行结束符转换成本地格式
QIODeviceBase.OpenModeFlag.Unbuffered                                           # 不使用缓存
QIODeviceBase.OpenModeFlag.NewOnly                                              # 创建和打开新文件时,只用于QFile设备,如果文件存在,打开将会失败,该模式是只写模式
QIODeviceBase.OpenModeFlag.ExistingOnly                                         # 打开文件时,如果文件不存在会出现错误,只适用于QFile设备

  读写设备分为两种,一种是 随机设备(random-access device),另一种是 顺序设备(sequential device),用 isSequential() 方法可以 判断设备是否是顺序设备QFileQBuffer 是随机设备,QTcpSocketQProcess 是顺序设备。随机设备 可以 获取设备指针的位置,将指针指向指定的位置,从指定位置读取数据。而顺序设备 只能依次读取数据随机设备 可以用 seek(pos:int) 方法 定位,用 pos() 方法 获取位置

  读取数据 的常用方法如下:

getChar(c:bytes)                                                                # 读取一个字符,并存储到c中
peek(length:int) -> QByteArray                                                  # 读取指定数量的字节
read(length:int) -> QByteArray                                                  # 表示读取指定长度的数据
readLine(length:int=0)                                                          # 读取一行数据,参数maxlen表示允许读取的最大长度,若为0表示不受限制
readData(length:int) -> QObject                                                 # 读取数据
readAll() -> QByteArray                                                         # 读取所有数据

  写入数据 的常用方法如下:

putChar(c:str) -> bool:                                                         # 写入一个字符
write(data:Union[QByteArray, bytes]) -> int                                     # 写入字符串,返回实际写入的字节数
writeData(data:bytes, len:int) -> int                                           # 写入数据,返回实际写入的字节数量

  一些顺序设备支持多通道读写,这些通道表示独立的数据流,可以用 setCurrentReadChannel(int) 方法设置读取通道,用 setCurrentWriteChannel(int) 方法设置写入通道,用 currentReadChannel() 方法和 currentWriteChannel() 方法获取读取和写入通道。

如果要继承 QIODevice 创建自己的读写设备,需要重写 readData()writeData() 函数。

1.2、QByteArray类

  在利用 QIODevice 的子类进行读写数据时,通常返回值或参数是 QByteArray 类型的数据。QByteArray 用于 存储二进制数据,至于这些数据到底表示什么内容(字符串、数字、图片或音频等),完全由程序的解析方式决定。如果采用合适的字符编码方式(字符集),字节数组可以恢复成字符串,字符串也可以转换成字节数组。字节数组会自动添加 "\0" 作为结尾,统计字节数组的长度时,不包含末尾的 "\0"

  用 QByteArray 创建字节数组的方法如下,其中 c 只能是一个字符。

QByteArray()
QByteArray(text:bytes, size:int=-1)
QByteArray(text:Union[QByteArray, bytes, bytearray str])
QByteArray(size:int, c:str)

  用 Python 的 str(byteArray:QByteArray, encoding:str="utf-8") 函数可以将 QByteArray 数据转换成 Python 的字符串型数据。用 QByteArrayappend(data:str) 方法可以将 Python 的字符串添加到 QByteArray 对象中,同时返回包含字符串的新 QByteArray 对象。

  Python3.x 中新添加了字节串 bytes 数据类型,其功能与 QByteArray 的功能类似。如果一个字符串前面加 "b",就表示是 bytes 类型的数据,例如 b'hello'

  bytes 数据和字符串的对比如下:

  • 字节是计算机的语言,字符串是人类的语言,它们之间通过编码表形成对应关系。
  • 字符串由若干个字符组成,以字符为单位进行操作。
  • bytes 由若干个字节组成,以字节为单位进行操作。
  • bytes 和字符串除了操作的数据单元不同之外,它们支持的所有方法都基本相同。
  • bytes 和字符串都是不可变序列,不能随意增加和删除数据。

  用 xx=bytes("hello", encoding="utf-8") 方法可以将字符串 "hello" 转换成 bytes,用 yy=str(xx, encoding="utf-8")方法可以将 bytes 转换成字符串。

  bytes 也是一个类,用 bytes() 方法可以创建一个空 bytes 对象,用 bytes(int) 方法可以创建指定长度的 bytes 对象,用 decode(encoding:str="utf-8") 方法可以对数据进行解码,bytes 的操作方法类似于字符串的操作方法。

  Python 中还有一个与 bytes 类似但是可变的数组 bytearray,其创建方法和字符串的转换方法与 bytes 相同,在 QByteArray 的各个方法中,可以用 bytes 数据的地方也可以用 bytearray

  QByteArray 类的常用方法:

# 实例方法
append(a:Union[QByteArray, bytes]) -> QByteArray                                # 在末尾追加数据
append(c:str) -> QByteArray                                                     # 在末尾追加字符串
append(count:int, c:str) -> QByteArray                                          # 在末尾追加字符串
append(s:bytes, len:int) -> QByteArray                                          # 在末尾追加字符串

at(i:int) -> str                                                                # 根据索引获取数据
chop(n:int) -> QByteArray                                                       # 获取从末尾移除len个字节后的字节数组
clear() -> None                                                                 # 清空所有字节

contains(bv:Union[QByteArray, bytes]) -> bool                                   # 获取是否包含指定的字节数组
contains(c:str) -> bool                                                         # 获取是否包含指定的字符串

count(bv:Union[QByteArray, bytes]) -> int                                       # 获取指定的字节数组的出现次数
count() -> int                                                                  # 获取字节数组的长度
size() -> int                                                                   # 获取字节数组的长度

data() -> bytes                                                                 # 获取字符串

startsWith(bv:Union[QByteArray, bytes]) -> bool                                 # 获取是否以指定的字节数组开头
startsWith(c:str) -> bool                                                       # 获取是否以指定的字符串开头
endsWith(bv:Union[QByteArray, bytes]) -> bool                                   # 获取末尾是否时指定的字节数组
endsWith(c:str) -> bool                                                         # 获取末尾是否是指定的字符串

fill(c:str, size:int=-1) -> QByteArray                                          # 使数组的每个数据为指定的字符,将长度调整为size

indexOf(bv:Union[QByteArray, bytes], from:int=0) -> int                         # 获取指定的字节数组在数组中的位置
indexOf(c:str, from:int=0) -> int                                               # 获取指定的字符串在数组中的位置

insert(i:int, bv:Union[QByteArray, bytes]) -> QByteArray                        # 在指定的位置插入字节数组
insert(i:int, c:str) -> QByteArray                                              # 在指定的位置插入字符串
insert(i:int, count:int, c:str) -> QByteArray                                   # 在指定的位置插入字符串

isEmpty() -> bool                                                               # 是否为空,长度为0时返回True
isNull() -> bool                                                                # 内容为空返回True

toLower() -> QByteArray                                                         # 将所有字符转换为小写
isLower() -> bool                                                               # 判断是否全部都是小写
toUpper() -> QByteArray                                                         # 将所有字符转换为大写
isUpper() -> bool                                                               # 判断是否全部都是大写

lastIndexOf(bv:Union[QByteArray, bytes], from:int=-1) -> int                    # 获取最后索引值
lastIndexOf(c:str, from:int=-1) -> int                                          # 获取最后索引值

length() -> int                                                                 # 获取字节数组的长度
mid(index:int, len:int=-1) -> QByteArray                                        # 从指定位置获取指定长度的数据

prepend(a:Union[QByteArray, bytes]) -> QByteArray                               # 在开头插入字节数组
remove(index:int, len:int) -> QByteArray                                        # 从指定位置删除指定长度的数据
repeated(times:int) -> QByteArray                                               # 获取重复times次后的数据
replace(index:int, len:int, s:Union[QByteArray, bytes]) -> QByteArray           # 从指定位置替换指定长度的数据
replace(before:Union[QByteArray, bytes], after:Union[QByteArray, bytes]) -> QByteArray  # 替换指定位置的数据

resize(size:int) -> None                                                        # 调整长度

setNum(arg__1:float, format:str="g", precision:int=6) -> QByteArray             # 将浮点数转换成科学计数法数据
setNum(arg__1:int, base:int=10) -> QByteArray                                   # 将整数转换成字节数组

split(sep:str) -> List[QByteArray]                                              # 用分割符将字节数组分割成列表
squeeze() -> None                                                               # 释放不存储数据的内存

toBase64(options:QByteArray.Base64Option=QByteArray.Base64Option.Base64Encoding) -> QByteArray  # 将字节数组转换为Base64编码
toDouble() -> Tuple[float, bool]                                                # 转换成浮点数
toFloat() -> Tuple[float, bool]                                                 # 转换成浮点数
toHex(separator:str="0") -> QByteArray                                          # 转换成十六进制

toShort(base:int=10) -> Tuple[int, bool]                                        # 根据进制转换成整数 
toInt(base:int=10) -> Tuple[int, bool]                                          # 根据进制转换成整数
toLong(base:int=10) -> Tuple[int, bool]                                         # 根据进制转换成整数
toLongLong(base:int=10) -> Tuple[int, bool]                                     # 根据进制转换成整数

toUShort(base:int=10) -> Tuple[int, bool]                                       # 根据进制转换成整数
toUInt(base:int=10) -> Tuple[int, bool]                                         # 根据进制转换成整数
toULong(base:int=10) -> Tuple[int, bool]                                        # 根据进制转换成整数
toULongLong(base:int=10) -> Tuple[int, bool]                                    # 根据进制转换成整数

# 转换成百分比编码
toPercentEncoding(exclude:QByteArray=QByteArray(), include:QByteArray=QByteArray(), percent="%") -> QByteArray  

simplified() -> QByteArray                                                      # 去除内部、开始和结尾的空白字符

left(len:int) -> QByteArray                                                     # 从左侧获取指定长度的字节
right(len:int) -> QByteArray                                                    # 从右侧获取指定长度的字节
truncate(pos:int) -> None                                                       # 截断前pos个字符数据

# 静态方法
# 从Base645编码中解码
fromBase64(base64:Union[QByteArray, bytes], options:QByteArray.Base64Option=QByteArray.Base64Option.Base64Encoding) -> QByteArray
# 从Base64编码中解码
fromBase64Encoding(base64:Union[QByteArray, bytes], options:QByteArray.Base64Option=QByteArray.Base64Option.Base64Encoding) -> QByteArray

fromHex(hexEncoded:Union[QByteArray, bytes]) -> QByteArray                      # 从十六进制数据中解码
fromRawData(data:Union[QByteArray, bytes], size:int=-1) -> QByteArray           # 用前size个原生字节构建字符数组
fromPercentEncoding(pctEncoded:Union[QByteArray, bytes], percent:str="%") -> QByteArray # 从百分号编码中解码

number(arg__1:int, base:int=10) -> QByteArray                                   # 将整数转换为字节数组
number(arg__1:float, format:str="g", precision:int=6)                           # 将浮点数转换为字节数组

  用 setNum(float,format='g',precision=6) 方法或 number(float,format='g',precision=6) 方法可以 将浮点数转换成用科学计数法表示的数据,其中格式 format 可以取 'e''E''f''g''G''e' 表示的格式如 -9.9e+999,'E' 表示的格式如 9.9E+999,'f' 表示的格式如 9.9,如果取 'g' 表示视情况选择 'e''f',如果取 'G' 表示视情况选择 'E''f'

  用静态方法 fromBase64(Union[QByteArray,bytes],options=QByteArray.Base64Encoding) 可以 把 Base64 编码数据解码,用 toBase64(options:QByteArray.Base64Option) 方法可以 转换成 Base64 编码,其中参数 options 可以取值如下:

QByteArray.Base64Option.Base64Encoding
QByteArray.Base64Option.Base64UrlEncoding
QByteArray.Base64Option.KeepTrailingEquals
QByteArray.Base64Option.OmitTrailingEquals
QByteArray.Base64Option.IgnoreBase64DecodingErrors
QByteArray.Base64Option.AbortOnBase64DecodingErrors

1.3、QFile读取数据

  QFile 继承自 QIODevice,会继承 QIODevice 的方法。QFile 可以读写文本文件和二进制文件,可以单独使用,也可以与 QTextStreamQDataStream 一起使用。

  用 QFile 类创建实例对象的方法如下所示:

QFile()
QFile(parent:QObject)
QFile(name:Union[str, bytes, os.PathLike])
QFile(name:Union[str, bytes, os.PathLike], parent:QObject)

  其中 parent 是继承自 QObject 的实例,name要打开的文件

  QFile 类的常用方法:

# 实例方法
open(flags:QIODeviceBase.OpenMode) -> None                                      # 按照模式打开文件
setFileName(name:Union[str, bytes, os.PathLike]) -> None                        # 设置文件路径和名称
fileName() -> str                                                               # 返回文件名称
flush() -> None                                                                 # 将缓存中的数据写入到文件中
close() -> None                                                                 # 关闭文件

# 静态方法
setPermissions(filename:QFileDevice.Permission)                                 # 设置权限
exists(fileName:str) -> bool                                                    # 检查文件是否存在
copy(fileName:str, newName:str) -> None                                         # 复制打开的文件到新文件
remove(fileName:str) -> None                                                    # 删除文件
rename(oldName:str, newName:str) -> None                                        # 重命名文件

  新建一个 template.py 文件。

from PySide6.QtCore import QFile

if __name__ == "__main__":
    file_path = "./文件.txt"
    file = QFile(file_path)                                                     # 1.创建一个文件信息

    file.open(QFile.OpenModeFlag.WriteOnly)                                     # 2.以只写模式打开文件

    file.write("你好,世界!\n".encode("utf-8"))                                  # 3.向文件中写入内容
    file.write("hello world!\n".encode("utf-8"))

    file.close()                                                                # 4.关闭文件
  
    file.open(QFile.OpenModeFlag.ReadOnly)                                      # 5.以只读模式打开文件

    while not file.atEnd():                                                     # 6.判断是否读到末尾
        text = file.readLine().toStdString().strip()                            # 7.从文件中读取一行
        print(text)
  
    file.close()                                                                # 8.关闭文件

二、用流方式读取数据

  从本机上读写数据更简便的方法是用流(stream)方式,读写文本数据用 文本流 QTextStream,读写二进制数据用 数据流 QDataStream。用 数据流 可以将文本、整数和浮点数以 二进制格式 保存到文件中,也可以将常用的类的实例保存到文件中,可以从文件中直接读取类的实例。

2.1、文本流

  文本流 是指一段文本数据,可以理解成管道中流动的一股水,管道接到什么设备上,水就流入什么设备内。QTextStream文本流类,它可以连接到 QIODeviceQByteArray 上,可以将一段文本数据写入 QIODeviceQByteArray 上,或者从 QIODeviceQByteArray 上读取文本数据。QTextStream 适合写入大量的有一定格式要求的文本。

  用 QTextStream 定义文本流的方法如下所示,可以看出其连接的设备可以是 QIODeviceQByteArray

QTextStream()
QTextStream(device:QIODevice)
QTextStream(array:Union[QByteArray, bytes], openMode=QIODeviceBase.ReadWrite)

  QTextStream 类的常用方法如下:

setDevice(device:QIODevice) -> None                                             # 设置操作的设备
device() -> QIODevice                                                           # 获取操作的设备

setEncoding(encoding:QStringConverter.Encoding) -> None                         # 设置编码
encoding() -> QStringConverter.Encoding                                         # 获取编码
setAutoDetectUnicode(enabled:bool) -> None                                      # 设置自动检测编码
setGenerateByteOrderMark(generate:bool) -> None                                 # 如果设置成True,那么在写入文件时,会写入BOM

setFieldWidth(width:int) -> None                                                # 设置数据流的宽度,如果为0,则宽度时数据的宽度
fieldWidth() -> int                                                             # 获取数据流的宽度

setFieldAlignment(alignment:QTextStream.FieldAlignment) -> None                 # 设置数据在数据流内的对齐方式
fieldAlignment() -> QTextStream.FieldAlignment                                  # 获取数据在数据流内的对齐方式

setPadChar(ch:str) -> None                                                      # 设置填充字符
padChar() -> str                                                                # 获取填充字符

setIntegerBase(base:int) -> None                                                # 设置整数的进制
integerBase() -> int                                                            # 获取整数的进制

setNumberFlags(flags:QTextStream.NumberFlags) -> None                           # 设置数字的标识
numberFlags() -> QTextStream.NumberFlags                                        # 获取数字的标识

setRealNumberNotation(notation:QTextStream.NumberNotation) -> None              # 设置实数的标记方法
realNumberNotation() -> QTextStream.NumberNotation                              # 获取实数的标记方法
setRealNumberPrecision(precision:int) -> None                                   # 设置实数的精度
realNumberPrecision() -> int                                                    # 获取实数的精度

setStatus(status:QTextStream.Status) -> None                                    # 设置状态
status() -> QTextStream.Status                                                  # 获取状态
resetStatus() -> None                                                           # 重置状态

read(maxlen:int) -> str                                                         # 读取指定长度的数据
readAll() -> str                                                                # 读取所有数据
readLine(maxlen:int=0) -> str                                                   # 按行读取数据,maxlen是一次允许度的最大长度

seek(pos:int) -> None                                                           # 定位到指定位置
pos() -> int                                                                    # 获取当前位置
flush() -> None                                                                 # 将缓存中的数据写到设备中
atEnd() -> bool                                                                 # 判断是否已经到达文件末尾
skipWhiteSpace() -> None                                                        # 忽略空字符,直到非空字符或达到末尾
reset() -> None                                                                 # 重置除字符串和缓冲以外的其它设置

  QTextStream 的连接设备可以在创建文本数据流时定义,也可以用 setDevice(device:QIODevice) 方法来定义,用 device() 方法 获取连接的设备QTextStreamQFile 结合可读写文本文件,与 QTcpSocketQUdpSocket 结合可读写网络文本数据。

  QTextStream 没有专门的写数据的方法,需要用流操作符 "<<" 来完成写入数据。"<<" 的左边是 QTextStream 实例,右边可以是字符串、整数或浮点数,如果要同时写入多个数据,可以把多个 "<<" 写到一行中。

  用 setEncoding(QStringConverter.Encoding) 方法 设置文本流读写数据的编码,文本流支持的编码如下:

QStringConverter.Encoding.Utf8
QStringConverter.Encoding.Utf16
QStringConverter.Encoding.Utf16LE
QStringConverter.Encoding.Utf16BE
QStringConverter.Encoding.Utf32
QStringConverter.Encoding.Utf32LE
QStringConverter.Encoding.Utf32BE
QStringConverter.Encoding.Latin1
QStringConverter.Encoding.System                                                # 系统默认的编码

  用 setAutoDetectUnicode(on:bool) 方法 设置是否自动识别编码,如果能识别出则会替换已经设置的编码。如果 setGenerateByteOrderMark(generate:bool)True 且采用 UTF 编码,会在写入数据前在数据前面添加自动查找编码标识 BOM(byte-order mark),即字节顺序标记,它是插入到以 UTF-8、UTF-16 或 UTF-32 编码 Unicode 文件开头的特殊标记,用来识别 Unicode 文件的编码类型。

  用 setFieldWidth(width:int=0) 方法 设置写入一段数据流的宽度,如果真实数据流的宽度小于设置的宽度,可以用 setFieldAlignment(allignment:QTextStream.FieldAlignment) 方法 设置数据在数据流内的对齐方式,其余位置的数据用 setPadChar(c:str) 设置的字符来填充。参数 allignmentQTextStream.FieldAlignment 类型的枚举参数,用于 指定对齐方式,可以取值如下:

QTextStream.FieldAlignment.AlignLeft                                            # 左对齐
QTextStream.FieldAlignment.AlignRight                                           # 右对齐
QTextStream.FieldAlignment.AlignCenter                                          # 居中
QTextStream.FieldAlignment.AlignAccountingStyle                                 # 居中,但数值的符号位靠左

  用 setNumberFlags(flag:QTextStream.NumberFlag) 方法 设置输出整数和浮点数时数值的表示样式,其中参数 flagQTextStream.NumberFlag 类型的枚举值,可以取值如下:

QTextStream.NumberFlag.ShowBase                                                 # 以进制作为前缀
QTextStream.NumberFlag.ForcePoint                                               # 强制显示小数点
QTextStream.NumberFlag.ForceSign                                                # 强制显示正负号
QTextStream.NumberFlag.UppercaseBase                                            # 进制显示成大写
QTextStream.NumberFlag.UppercaseDigits                                          # 表示10~35的字母用大写

  用 setRealNumberNotation(notation:QTextStream.RealNumberNotation) 方法 设置浮点数的标记方法,参数 notationQTextStream.RealNumberNotation 类型的枚举值,可以取值如下:

QTextStream.RealNumberNotation.ScientificNotation                               # 科学计数法
QTextStream.RealNumberNotation.FixedNotation                                    # 固定小数点
QTextStream.RealNumberNotation.SmartNotation                                    # 视情况选择合适的方法

  用 setStatus(status:QTextStream.Status) 方法 设置数据流的状态,参数 statusQTextStream.Status 类型的枚举值,可以取值如下:

QTextStream.Status.Ok                                                           # 文本流正常
QTextStream.Status.ReadPastEnd                                                  # 读取过末尾
QTextStream.Status.ReadCorruptData                                              # 读取了有问题的数据
QTextStream.Status.WriteFailed                                                  # 不能写入数据

  修改 template.py 文件的内容。

from PySide6.QtCore import QFile, QTextStream, QStringConverter

if __name__ == "__main__":
    file_path = "./文件.txt"
    file = QFile(file_path)                                                     # 1.创建一个文件信息

    file.open(QFile.OpenModeFlag.WriteOnly)                                     # 2.以只写模式打开文件

    writer = QTextStream(file)                                                  # 3.创建文本流

    writer.setEncoding(QStringConverter.Encoding.Utf8)                          # 4.设置编码
    writer.setFieldWidth(0)                                                     # 5.设置域宽
    writer.setFieldAlignment(QTextStream.FieldAlignment.AlignCenter)            # 6.设置对齐方式

    writer << "你好,世界!\n"                                                    # 7.写入数据
    writer << "hello world!\n"
  
    writer.flush()                                                              # 8.刷新写入
    file.close()                                                                # 9.关闭文件

    file.open(QFile.OpenModeFlag.ReadOnly)                                      # 10.以只读模式打开信息

    while not file.atEnd():                                                     # 11.判断是否读到末尾
        text = file.readLine()                                                  # 12.从文件中读取一行
        print(str(text, encoding="utf-8").strip())

    file.close()                                                                # 13.关闭文件

2.2、数据流

  数据流 QDataStream 用于 直接读写二进制的数据和网络通信数据,二进制数据具体表示的物理意义由读写方法以及后续的解码决定,数据流的读写与具体的操作系统无关。

  用 QDataStream 类创建数据流对象的方法如下所示,它可以连接到继承自 QIODevice 的设备或 QByteArray 上。

QDataStream()
QDataStream(device:QIODevice)
QDataStream(device:Union[QByteArray, bytes])
QDataStream(device:Union[QByteArray, bytes], flags:QIODeviceBase.OpenMode)

  QDataStream 类的常用方法如下:

setDevice(device:QIODevices) -> None                                            # 设置设备

setByteOrder(arg__1:QDataStrem.ByteOrder) -> None                               # 设置字节序
byteOrder() -> QDataStrem.ByteOrder                                             # 获取字节序

setFloatingPointPrecision(precision:QDataStrem.FloatingPointPrecision) -> None  # 设置读写浮点数的精度

setStatus(status:QDataStrem.Status) -> None                                     # 设置流状态
resetStatus() -> None                                                           # 重置流状态
status() -> QDataStrem.Status                                                   # 获取流状态

setVersion(version:int) -> None                                                 # 设置版本号
version() -> int                                                                # 获取版本号

skipRawData(len:int) -> int                                                     # 跳过原生数据,返回跳过的字节数量

commitTransaction() -> None                                                     # 完成数据块

rollbackTransaction() -> None                                                   # 回到数据块的记录点
abortTransaction() -> None                                                      # 放弃对数据块的记录

atEnd() -> bool                                                                 # 获取是否还有数据可读

  创建数据流对象时,可以设置数据流关联的设备,也可用 setDevice(device:QIODevice) 方法 重新设置关联的设备,用 device() 方法 获取关联的设备。用 setVersion(version:int) 方法 设置版本号。不同版本号的数据的存储格式有所不同,因此建议设置版本号。到目前为止,版本号可取值如下:

QDataStream.Qt_1_0
QDataStream.Qt_2_0
QDataStream.Qt_3_0
QDataStream.Qt_3_1
QDataStream.Qt_3_3
QDataStream.Qt_4_0 ~ QDataStream.Qt_4_9
QDataStream.Qt_5_0 ~ QDataStream.Qt_5_15
QDataStream.Qt_6_0 ~ QDataStream.Qt_6_2

  用 setFloatingPointPrecision(precision:QDataStream.FloatingPointPrecision) 方法 设置读写浮点数的精度,其中参数 precisionQDataStream.FloatingPointPrecision 类型的枚举值,可以取值如下:

QDataStream.FloatingPointPrecision.SinglePrecision
QDataStream.FloatingPointPrecision.DoublePrecision

  对于版本高于 Qt_4_6 且精度设置为 DoublePrecision 的浮点数是 64 位精度,对于版本高于 Qt_4_6 且精度设置为 SinglePrecision 的浮点数是 32 位精度。

  用 setByteOrder(order:QDataStream.ByteOrder) 方法 设置字节序,参数 orderQDataStream.ByteOrder 类型的枚举值,可以取值如下:

QDataStream.ByteOrder.BigEndian                                                 # 大端字节序,默认值
QDataStream.ByteOrder.LittleEndian                                              # 小端字节序

大端字节序的高位字节在前,低位字节在后,小端字节序与此相反。

  用 skipRawData(length:int) 方法可以 跳过指定长度的原生字节返回真实跳过的字节数。原生数据是机器上存储的二进制数据,需要用户自己解码。

  用 startTransaction() 方法可以 记录一个读数据的点,对于顺序设备会在内部复制读取的数据,对于随机设备会保存当前数据流的位置。用 commitTransaction() 方法 确认完成记录一个数据块,当数据流的状态是已经超过末尾时,用该方法会回到数据块的记录点,如果状态是数据有误,则会放弃记录的数据块。用 rollbackTransaction() 方法 在确认完成记录数据块之前返回到记录点。用 abortTransaction() 方法 放弃对数据块的记录,并不影响当前读数据的位置。

  数据流用于读/写整数、浮点数和逻辑值的方法和数值的范围如下所示。需要特别注意的是,在读数值时,必须按照写入数值时所使用的字节数来读,否则读取的数值不是写入时的数值。

readInt8() -> int                                                               # 在1个字节上读带正负号整数
writeInt8(arg__1:int) -> None                                                   # 在1个字节上写带正负号整数

readInt16() -> int                                                              # 在2个字节上读带正负号整数
writeInt16(arg__1:int) -> None                                                  # 在2个字节上写带正负号整数

readInt32() -> int                                                              # 在4个字节上读带正负号整数
writeInt32(arg__1:int) -> None                                                  # 在4个字节上写带正负号整数

readInt64() -> int                                                              # 在8个字节上读带正负号整数
writeInt64(arg__1:int) -> None                                                  # 在8个字节上写带正负号整数

readUInt8() -> int                                                              # 在1个字节上读无符号整数
writeUInt8(arg__1:int) -> None                                                  # 在1个字节上写无符号整数

readUInt16() -> int                                                             # 在2个字节上读无符号整数
writeUInt16(arg__1:int) -> None                                                 # 在2个字节上写无符号整数

readUInt32() -> int                                                             # 在4个字节上读无符号整数
writeUInt32(arg__1:int) -> None                                                 # 在4个字节上写无符号整数

readUInt64() -> int                                                             # 在8个字节上读无符号整数
writeUInt64(arg__1:int) -> None                                                 # 在8个字节上写无符号整数

readBool() -> int                                                               # 在1个字节上读逻辑值
writeBool(arg__1:int) -> None                                                   # 在1个字节上写逻辑值

readFloat() -> int                                                              # 在4个字节上读带正负号浮点数
writeFloat(arg__1:int) -> None                                                  # 在4个字节上写带正负号浮点数

readDouble() -> int                                                             # 在8个字节上读带正负号浮点数
writeDouble(arg__1:int) -> None                                                 # 在8个字节上写带正负号浮点数

  数据流用于读/写字符串的方法如下所示。读/写字符串时不需要指定字节数量,系统会根据字符串的大小来决定所使用的字节数。

readString() -> str                                                             # 读文本
writeString(arg__1:str) -> None                                                 # 写文本

readQString() -> List[str]                                                      # 读文本
writeQString(arg__1:Sequence[str]) -> None                                      # 写文本

readQStringList() -> List[str]                                                  # 读文本列表
writeQStringList(arg__1:Sequence[str]) -> None                                  # 写文本列表
from PySide6.QtCore import QFile, QDataStream

if __name__ == "__main__":
    file_path = "./文件.txt"
    file = QFile(file_path)                                                     # 1.创建一个文件信息

    file.open(QFile.OpenModeFlag.WriteOnly)                                     # 2.以只写模式打开文件

    writer = QDataStream(file)                                                  # 3.创建文本流

    writer.writeQString("你好,世界!\n")                                         # 4.向文件中写入数据
    writer.writeString("hello world!\n")
    writer.writeInt32(27185)
    writer.writeFloat(27185.27185)
  
    file.close()                                                                # 5.关闭文件

    file.open(QFile.OpenModeFlag.ReadOnly)                                      # 6.以只读模式打开文件

    value = writer.readQString().strip()                                        # 7.从文件中读取数据
    print(value)

    value = writer.readString().strip()
    print(value)

    value = writer.readInt32()
    print(value)

    value = writer.readFloat()
    print(value)
  
    file.close()                                                                # 8.关闭文件

三、临时数据的保存

3.1、临时文件

  QTemporaryFile 类用于创建临时文件,它继承自 QFile,当用 Open() 方法打开设备时创建临时文件,并保证临时文件名是唯一的,不会和本机上的文件同名。

  用 QTemporaryFile 创建临时文件对象的方法如下:

QTemporaryFile()
QTemporaryFile(parent:QObject)
QTemporaryFile(templateName:str)
QTemporaryFile(templateName:str, parent:QObject)

  其中 templateName文件名称模板,或者不用模板而用 指定文件名parent 是继承自 QObject 类的实例对象。模板的文件名中包含 6 个或 6 个以上的大写 "X",扩展名可以自己指定,例如 QTemporaryFile("XXXXXXXX.sdb")QTemporaryFile("abXXXXXXXXcd.sdb")

  如果没有使用模板,而使用 具体文件名,则 临时文件名是在文件名基础上添加新的扩展名,如果 指定了父对象,则用 应用程序的名称(用 app.setApplicationName(name:str) 设置)再加上新的扩展名作为临时文件名。如果 没有使用模板或指定文件名,则 存放临时文件的路径是系统临时路径,可以通过 QDir.tempPath() 方法 获取系统临时路径;如果使用模板或指定文件名,则存放到当前路径下,当前路径可以用 QDir.currentPath() 方法查询。

  QTemporaryFile 类常用方法如下:

open() -> bool                                                                  # 创建并打开临时文件
fileName() -> str                                                               # 获取临时文件名
setAutoRemove(b:bool) -> None                                                   # 设置是否自动删除临时文件
autoRemove() -> bool                                                            # 获取是否自动删除临时文件
setFileTemplate(name:str) -> None                                               # 设置临时文件的模板
fileTemplate() -> str                                                           # 获取临时文件的模板

  创建临时文件对象后,用 open() 方法 打开文件,这时会 生成临时文件,临时文件名可以用 fileName() 方法获取,临时文件的打开方式是读写模式(QIODeviceBase.OpenModeFlag.ReadWrite)。打开临时文件后,可以按照前面介绍的写入和读取方法来读写数据。用 setAutoRemove(on:bool) 方法 设置临时文件对象销毁后临时文件是否自动删除,默认为 True

3.2、临时路径

  与创建临时文件类似,也可以创建临时路径,应保证所创建的临时路径不会覆盖本机上的路径,程序退出时自动删除临时路径。

  创建临时路径的方法如下所示:

QTemporaryDir()
QTemporaryDir(templateName:str)

  QTemporaryDir 类常用方法如下:

path() -> str                                                                   # 获取创建的临时路径
isValid() -> bool                                                               # 检查临时路径是否创建成功
errorString() -> str                                                            # 获取错误信息
filePath(fileName:str) -> str                                                   # 获取临时路径中的文件的路径
setAutoRemove(b:bool) -> None                                                   # 设置是否自动移除临时路径
autoRemove() -> bool                                                            # 获取是否自动移除临时路径
remove() -> bool                                                                # 移除临时路径

3.3、存盘

  QSaveFile 用来 保存文本文件和二进制文件,在写入操作失败时不会导致已经存在的数据丢失。QSaveFile 执行写操作时,会先将内容写入到一个临时文件中,如果没有错误发生,则调用 commit() 方法来 将临时文件中的内容移到目标文件中。这样能确保目标文件中的数据在写操作发生错误时不会丢失,也不会出现部分写入的情况。

  一般使用 QSaveFile 在磁盘上保存整份文档。QSaveFile 会自动检测写入过程中所出现的错误,并记住所有发生的错误,在调用 commit() 方法时放弃临时文件。

  用 QSaveFile 创建保存文件的方法如下所示:

QSaveFile(parent:QObject=None)
QSaveFile(name:str)
QSaveFile(name:str, parent:QObject)

  其中 name文件名parent 是继承自 QObject 的对象。

  QSaveFile 常用方法如下:

setFileName(name:str) -> None                                                   # 设置保存数据的目标文件
fileName() -> str                                                               # 获取目标文件
open(mode:QIODeviceBase.OpenMode) -> bool                                       # 打开文件
commit() -> bool                                                                # 从临时文件中将数据写入到目标文件中
cancelWriting() -> None                                                         # 取消将数据写入到目标文件中
setDirectWriteFallback(enabled:bool) -> None                                    # 设置是否直接向目标文件中写数据
directWriteFallback() -> bool                                                   # 获取是否直接向目标文件中写数据
writeData(data:bytes, len:int) -> int                                           # 重写该函数,写入字符串,并返回实际写入的字节串的数量

  用 open(flags:QIODeviceBase.OpenMode) 方法 打开文件,并 创建临时文件,如果创建临时文件出错则返回 False。可以使用 QDataStreamQTextStream 进行读写,也可以使用从 QIODevice 继承的 read()readLine()write() 等方法进行读写。

  QSaveFile 不能调用 close() 函数,而是通过调用 commit() 函数 完成数据的保存。如果没有调用 commit() 函数,则 QSaveFile 对象销毁时,会丢弃临时文件。

  当应用程序出错时,用 cancelWriting() 方法可以 放弃写入的数据,即使又调用了 commit(),也不会发生真正保存文件操作。

  QSaveFile 会在目标文件的同一目录下创建一个临时文件,并自动进行重命名。但如果由于该目录的权限限制不允许创建文件,则调用 open() 会失败。

  为了解决这个问题,即能让用户编辑一个现存的文件,而不创建新文件,可使用 setDirectWriteFallback(True) 方法,这样在调用 open() 时就会 直接打开目标文件,并向其写入数据,而不使用临时文件。但是在写入出错时,不能使用 cancelWriting() 方法取消写入。

3.4、缓存

  对于程序中反复使用的一些临时数据,如果将其保存到文件中,则反复读取这些数据要比从缓存读取数据慢得多。缓存是 内存中一段连续的存储空间QBuffer 提供了可以从缓存读取数据的功能,在多线程之间进行数据传递时选择缓存比较方便。

  缓存属于共享资源,所有线程都能进行访问。QBufferQFile 一样,也是一种读写设备,它继承自 QIODevice,可以用 QIODevice 的读写方法从缓存中读写数据,也可以与 QTextStreamQDataStream 结合读写文本数据和二进制数据。

  用 QBuffer 创建缓存设备的方法如下:

QBuffer(parent=:QObject=None)
QBuffer(buffer:Union[QByteArray, bytes], parent=:QObject=None)

  其中 parent 是继承自 QObject 的实例对象。定义 QBuffer 需要一个 QByterArray 对象,也可不指定 QByteArray,系统会给 QBuffer 创建一个默认的 QByteArray 对象。

  QBuffer 类常用方法如下:

setBuffer(a:Union[QByteArray, byte]) -> None                                    # 设置缓存
buffer() -> QByteArray                                                          # 获取缓存中的QByteArray对象

setData(data:Union[QByteArray, byte]) -> None                                   # 给缓存设置QByteArray对象
data() -> QByteArray                                                            # 获取缓存中的QByteArray对象

open(mode:QIODeviceBase.OpenMode) -> bool                                       # 打开缓存
close() -> None                                                                 # 关闭缓存

readData(data:bytes, maxlen:int) -> object                                      # 重写该函数,读取指定的最大数量的字节数据
writeData(data:bytes, len:int) -> int                                           # 重写该函数,写入数据

canReadLine() -> bool                                                           # 获取是否可以按行读取

seek(pos:int) -> bool                                                           # 定位到指定位置
pos() -> int                                                                    # 获取指向缓存内部指针的位置
atEnd() -> bool                                                                 # 获取是否达到尾部

size() -> int                                                                   # 获取缓存中字节的总数

  默认情况下,系统会自动给 QBuffer 的实例创建默认的 QByteArray 对象,可以用 buffer() 方法或 data() 方法获取 QByteArray 对象,也可用 setBuffer(data:QByteArray) 方法 设置缓存QBuffer 需要用 open(mode:QIODeviceBase.OpenMode) 方法 打开缓存,成功则返回 True,打开后可以读写数据;用 close() 方法 关闭缓存

from PySide6.QtCore import QFile, QBuffer, QDataStream

if __name__ == "__main__":
    buffer = QBuffer()                                                          # 1.创建缓存
    buffer.open(QBuffer.OpenModeFlag.WriteOnly)                                 # 2.打开缓存
  
    writer = QDataStream(buffer)                                                # 3.创建文本流

    writer.writeQString("你好,世界!\n")                                         # 4.向文件中写入数据
    writer.writeString("hello world!\n")
    writer.writeInt32(27185)
    writer.writeFloat(27185.27185)

    buffer.close()                                                              # 5.关闭文件

    buffer.open(QFile.OpenModeFlag.ReadOnly)                                    # 6.以只读模式打开缓存

    value = writer.readQString().strip()                                        # 7.从缓存中读取数据
    print(value)

    value = writer.readString().strip()
    print(value)

    value = writer.readInt32()
    print(value)

    value = writer.readFloat()
    print(value)

    buffer.close()                                                              # 8.关闭文件

四、文件管理

4.1、文件信息

  文件信息 QFileInfo 用于 查询文件的信息,如文件的相对路径、绝对路径、文件大小、文件权限、文件的创建及修改时间等。

  用 QFileInfo 类创建文件信息对象的方法如下所示:

QFileInfo()
QFileInfo(file:QFileDevice)
QFileInfo(file:Union[str, bytes, os.PathLike])
QFileInfo(dir:Union[QDir, str], file:Union[str, bytes, os.PathLike])

  其中 file需要获取文件信息的文件QFileInfo(dir:QDir,file:str) 表示用 dir 路径下的 file 文件创建文件信息对象。

  QFileInfo 类的常用方法如下:

setFile(file:Union[str, bytes]) -> None                                         # 设置需要获取文件信息的文件
setFile(file:QFileDevice) -> None                                               # 设置需要获取文件信息的文件
setFile(dir:Union[QDir, str], file:str) -> None                                 # 设置需要获取文件信息的文件

setCaching(on:bool) -> None                                                     # 设置是否使用缓存
refresh() -> None                                                               # 刷新文件信息

absoluteDir() -> QDir                                                           # 获取绝对路径目录
absoluteFilePath() -> str                                                       # 获取绝对路径
absolutePath() -> str                                                           # 获取绝对路径

baseName() -> str                                                               # 获取第一个"."之前的文件名
completeBaseName() -> str                                                       # 获取最后一个"."之前的文件名

suffix() -> str                                                                 # 获取扩展名,不包含"."
completeSuffix() -> str                                                         # 获取第一个"."之后文件名,包含扩展名

fileName() -> str                                                               # 获取文件名,包含扩展名,不包含路径

path() -> str                                                                   # 获取路径,不包含文件名
filePath() -> str                                                               # 获取路径和文件名

canonicalFilePath() -> str                                                      # 获取绝对路径和文件名,路劲中不含链接符号和多余的".."及"."
canonicalPath() -> str                                                          # 获取绝对路径,路径中不含链接符号和多余的".."及"."

birthTime() -> QDateTime                                                        # 获取创建时间
lastModified() -> QDateTime                                                     # 获取最后修改时间
dir() -> QDir                                                                   # 获取路径
group() -> str                                                                  # 获取文件组   
exists() -> bool                                                                # 获取文件是否存在

isAbsolute() -> bool                                                            # 是否绝对路径
isDir() -> bool                                                                 # 是否为目录
isFile() -> bool                                                                # 是否为文件
isReadable() -> bool                                                            # 是否可读文件
isWritable() -> bool                                                            # 是否可写文件
isExecutable() -> bool                                                          # 是否可执行文件
isHidden() -> bool                                                              # 是否隐藏文件
isRelative() -> bool                                                            # 是否相对路径
isRoot() -> bool                                                                # 是否根目录
isShortcut() -> bool                                                            # 是否为快捷方式
isSymLink() -> bool                                                             # 是否为连接符号或快捷方式
isSymbolicLink() -> bool                                                        # 是否为连接符号

makeAbsolute() -> bool                                                          # 转换为绝对路径

owner() -> str                                                                  # 获取文件所有者
ownerId() -> int                                                                # 获取文件所有者ID

size() -> int                                                                   # 获取文件大小
symLinkTarget() -> str                                                          # 获取被链接文件的绝对路径

  可以在创建 QFileInfo 对象时 设置要获取文件信息的文件,也可以用 setFile(dir:Union[QDir,str],file:str)setFile(file:Union[str,bytes])setFile(file:QFileDevice) 方法 重新设置要获取文件信息的文件

  QFileInfo 提供了一个 refresh() 函数,用于 重新读取文件信息。如果想关闭该缓存功能,以确保每次访问文件时都能获取当前最新的信息,可以通过 setCaching(False) 方法来完成设置。

from PySide6.QtCore import QFile, QFileInfo

if __name__ == "__main__":
    file_path = "./文件.txt"
    file = QFile(file_path)                                                     # 1.创建一个文件信息

    file.open(QFile.OpenModeFlag.ReadWrite)                                     # 2.以读读写模式打开文件

    file.write("你好,世界!".encode("utf-8"))                                    # 3.向文件中写入内容

    file.close()                                                                # 4.关闭文件

    file_info = QFileInfo(file_path)                                            # 5.获取文件的详情信息对象

    # 6.读取文件的详情信息
    print("文件的大小:", file_info.size())
    print("文件上次修改的时间:", file_info.lastModified())
    print("文件上次读取的时间:", file_info.lastRead())
    print("文件是否可读:", file_info.isReadable())

4.2、路径管理

  路径管理 QDir 用于管理路径和文件,它的一些功能与 QFileInfo 的功能相同。

  用 QDir 创建路径管理对象的方法如下:

QDir(path:Union[QDir, str])
QDir(path:Union[str, bytes, os.PathLike])
QDir(path:Union[str, bytes, os.PathLike], nameFilter:str, sort:QDir.SortFlag=QDir.IgnoreCase, filter:QDir.Filters=QDir.AllEntries)

  其中,path路径nameFilter名称过滤器filters 是枚举类型 QDir.Filter,是 属性过滤器sort 是 枚举类型 QDir.SortFlag指定排序规则

  参数 filtersQDir.Filter 的类型的枚举值,可以取值如下:

QDir.Filter.Dirs                                                                # 列出满足条件的路径
QDir.Filter.AllDirs                                                             # 所有路径
QDir.Filter.Files                                                               # 文件
QDir.Filter.Drives                                                              # 驱动器
QDir.Filter.NoSymLinks                                                          # 没有链接文件
QDir.Filter.NoDot                                                               # 没有"."
QDir.Filter.NoDotDot                                                            # 没有".."
QDir.Filter.NoDotAndDotDot                                                      #  没有"."和".."
QDir.Filter.AllEntries                                                          # 所有路径、文件和驱动器
QDir.Filter.Readable                                                            # 可读文件
QDir.Filter.Writable                                                            # 可写文件
QDir.Filter.Executable                                                          # 可执行文件
QDir.Filter.Modified                                                            # 可修改文件
QDir.Filter.Hidden                                                              # 可隐藏文件
QDir.Filter.System                                                              # 系统文件
QDir.Filter.CaseSensitive                                                       # 区分大小写

  参数 sortQDir.SortFlag 类型的枚举值,可以取值如下:

QDir.SortFlag.Name
QDir.SortFlag.Time
QDir.SortFlag.Size
QDir.SortFlag.Type
QDir.SortFlag.Unsorted
QDir.SortFlag.NoSort
QDir.SortFlag.DirsFirst
QDir.SortFlag.DirsLast
QDir.SortFlag.Reversed
QDir.SortFlag.IgnoreCase
QDir.SortFlag.LocaleAware

  QDir 类常用方法如下:

# 实例方法
setPath(path:Union[str, bytes]) -> None                                         # 设置路径
path() -> str                                                                   # 获取路径

absolutePath() -> str                                                           # 获取绝对路径
absoluteFilePath(fileName:str) -> str                                           # 获取绝对路径

relativeFilePath(fileName:str) -> str                                           # 获取相对路径

canonicalPath() -> str                                                          # 获取不含"."和".."的路径

cd(dirName:str) -> bool                                                         # 更改路径
cdUp() -> bool                                                                  # 更改路径到上一级

dirName() -> str                                                                # 获取最后一级的目录或文件名

setNameFilters(nameFilters:Sequence[str]) -> None                               # 设置文件名过滤器
setFilter(filter:QDir.Filter) -> None                                           # 设置属性过滤器

setSorting(sort:QDir.SortFlag) -> None                                          # 设置排序规则

# 根据过滤器和排序规则,获取路径下的所有文件信息和子路径信息
entryInfoList(filters:QDir.Filter=QDir.Filter.NoFilter, sort:QDir.SortFlag=QDir.SortFlag.NoSort) -> List[QFileInfo]
entryInfoList(nameFilters:Sequence[str], filters:QDir.Filter=QDir.Filter.NoFilter, sort:QDir.SortFlag=QDir.Filter.NoFilter) - List[QFileInfo]
entryList(filters:QDir.Filter=QDir.Filter.NoFilter, sort:QDir.SortFlag=QDir.Filter.NoFilter) -> List[str]
entryList(nameFilters:Sequence[str], filters:QDir.Filter=QDir.Filter.NoFilter, sort:QDir.SortFlag=QDir.Filter.NoFilter) -> List[str]

exists() -> bool                                                                # 判断路径或文件是否存在
exists(name:str) -> bool                                                        # 判断路径或文件是否存在

isAbsolute() -> bool                                                            # 获取是否是绝对路径
isRelative() -> bool                                                            # 获取是否是相对路径
isRoot() -> bool                                                                # 获取是否是根路径
isReadable() -> bool                                                            # 获取文件是否可读

# 获取路径是否为空
isEmpty(filters:QDir.Filter=QDir.Filter.NoFilter=QDir.Filters(QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot))

makeAbsolute() -> bool                                                          # 转换到绝对路径

mkdir(dirName:str) -> bool                                                      # 创建子路径,路径已存在,则返回False
mkpath(dirPath:str) -> bool                                                     # 创建多级目录,成功返回True

refresh() -> None                                                               # 刷新缓存

remove(fileName:str) -> bool                                                    # 移除文件 

removeRecursively() -> bool                                                     # 删除目录
rmdir(dirName:str) -> bool                                                      # 删除目录
rmpath(dirPath:str) -> bool                                                     # 删除目录

rename(oldName:str, newName:str) -> bool                                        # 重命名文件或目录

# 静态方法
cleanPath(path:str) -> str                                                      # 返回移除多余符号的路径

drives() -> List[QFileInfo]                                                     # 获取根文件信息列表

setSearchPaths(prefix:str, searchPaths:Sequence[str]) -> None                   # 设置搜索路径

home() -> QDir                                                                  # 获取系统的用户路径
homePath() -> str                                                               # 获取系统的用户路径

isAbsolutePath(path:str) -> bool                                                # 判断路径是否是绝对路径
isRelativePath(path:str) -> bool                                                # 判断路径是否是相对路径

listSeparator() -> str                                                          # 获取系统列表分割符
separator() -> str                                                              # 获取系统路径分割符

root() -> QDir                                                                  # 获取根目录
rootPath() -> str                                                               # 获取根目录

setCurrent(path:str) -> bool                                                    # 设置当前路径

temp() -> QDir                                                                  # 获取临时目录
tempPath() -> str                                                               # 获取临时目录

fromNativeSeparators(pathName:str) -> str                                       # 获取用"/"分割的路径

toNativeSeparators(pathName:str) -> str                                         # 转换成用本机系统使用的分割符分割的路径

  修改 template.py 文件的内容。

from PySide6.QtCore import QDir

if __name__ == "__main__":
    path = "./template/test"
    dir = QDir(path)                                                            # 1.创建一个文件信息

    # 2.如果文件夹不存在,则创建
    if not dir.exists(path):
        dir.mkdir(path)

    dir.cd("E://")                                                              # 3.切换目录

    print("是否是根目录:", dir.isRoot())
    print("是否是绝对路径:", dir.isAbsolute())
    print("是否是相对路径:", dir.isRelative())
    print("是否可读:", dir.isReadable())

    dir_list = dir.entryList()
    for item in dir_list:
        print(item)

4.3、文件和路劲监视器

  QFileSystemWatcher文件和路径监视器,当被监视的文件或路径发生修改、添加和删除等变化时会发送相应的信号,被监视的文件和路径一般不超过 256 个。

  用 QFileSystemWatcher 定义文件监视器对象的方法如下所示:

QFileSystemWatcher(parent:QObject=None)
QFileSystemWatcher(paths:Sequence[str], parent:QObject=None)

  其中 parent 是继承自 QObject类的实例对象;paths字符串列表,是 被监视的文件或路径

  QFileSystemWatcher 类常用方法:

addPath(file:str) -> bool                                                       # 添加被监视的路径或文件,成功返回True
addPaths(files:Sequence[str]) -> List[str]                                      # 添加被监视的路径或文件,返回没有添加成功的路径和文件列表
directories() -> List[str]                                                      # 获取被监视的路径列表
files() -> List[str]                                                            # 获取被监视的文件列表
removePath(file:str) -> bool                                                    # 将被监视的路径或文件从监视中移除,成功返回True
removePaths(files:Sequcence[str]) -> List[str]                                  # 移除被监视的路径或文件,返回没有移除成功的路径和文件列表

  QFileSystemWatcher 类常用信号:

directoryChanged(path:str)                                                      # 当被监视的路径发生改变时发射信号
fileChanged(path:str)                                                           # 当被监视的文件发生改变时发射信号

  用 addPath(file:str) 方法或 addPaths(files:Sequence[str]) 方法 添加被监视的路径或文件。用 removePath(file:str) 方法或 removePaths(files:Sequence[str]) 方法 移除被监视的文件或路径。用 directories() 方法 获取被监视的路径列表。用 files() 方法 获取被监视的文件列表。当被监视的路径发生改变(增加和删除文件及路径)或文件发生改变(修改、重命名、删除)时,会分别发送 directoryChanged(path) 信号和 fileChanged(fileName) 信号。

posted @ 2025-01-17 20:48  星光映梦  阅读(110)  评论(0)    收藏  举报