文件QFile
QFile 继承自QIODevice,会继承 QIODevice 的方法,
QFile 可以读写文本文件和二进制文件,可以单独使用,也可以与QTextStream 和 QDataStream 一起使用。
用QFile类创建实例对象的方法如下所示,其中 parent 是继承自QObject 的实例,str 是要打开的文件需要注意的是,文件路径中的分隔符可以用/
、//
,而不能用\
from PySide6.QtCore import QFile
QFile(self)-> None
QFile(name: Union[str,bytes,os.PathLike])-> None
QFile(name: Union[str,bytes,os.PathLike],parent: PySide6.QtCore.QObject)-> None
QFile(parent: PySide6.QtCore.QObject)-> None
QFile的说明
QFile是一种用于读取和写入文本、二进制文件和资源的I/O设备。QFile可以自己使用,或者更方便地与QTextStream或QDataStream一起使用。
文件名通常在构造函数中传递,但可以随时使用setFileName()进行设置。QFile要求文件分隔符为"/“,而与操作系统无关。不支持使用其他分隔符(例如”")。
您可以使用exists()检查文件是否存在,并使用remove()删除文件。(QFileInfo和QDir提供了更高级的文件系统相关操作。)
该文件使用open()打开,使用close()关闭,并使用flush()刷新。数据通常使用QDataStream或QTextStream进行读取和写入,但您也可以调用QIODevice-继承的函数read()、readLine()、readAll()、write()。QFile还继承了getChar()、putChar()和ungetChar(),它们一次处理一个字符。
文件的大小由size()返回。您可以使用pos()获取当前文件位置,也可以使用seek()移动到新的文件位置。如果您已经到达文件的末尾,atEnd()将返回true。
直接读取文件
以下示例逐行读取文本文件:
file = QFile("in.txt")
if not file.open(QIODevice.ReadOnly | QIODevice.Text):
return
while not file.atEnd():
line = file.readLine()
process_line(line)
传递给open()的QIODevice::Text标志告诉Qt将Windows样式的行终止符(“\r\n”)转换为C++样式的行结束符(“\n”)。默认情况下,QFile采用二进制,即不对文件中存储的字节执行任何转换。
使用流读取文件
下一个示例使用QTextStream逐行读取文本文件:
file = QFile("in.txt")
if not file.open(QIODevice.ReadOnly | QIODevice.Text):
return
in = QTextStream(file)
while not in.atEnd():
line = in.readLine()
process_line(line)
QTextStream负责将存储在磁盘上的8位数据转换为16位Unicode QString。默认情况下,它假设文件是用UTF-8编码的。这可以使用setEncoding()进行更改。
要编写文本,我们可以使用运算符<<(),它被重载以在左侧获取QTextStream,在右侧获取各种数据类型(包括QString):
file = QFile("out.txt")
if not file.open(QIODevice.WriteOnly | QIODevice.Text):
return
out = QTextStream(file)
out <<"The magic number is:"<< 49 <<"\n"
QDataStream与此类似,可以使用运算符<<()写入数据,使用运算符>>()读取数据。有关详细信息,请参阅类文档。
信号
与其他QIODevice实现(如QTcpSocket)不同,QFile不发出aboutToClose()、bytesWritten()或readyRead()信号。这种实现细节意味着QFile不适合读取和写入某些类型的文件,例如Unix平台上的设备文件。
平台特定问题
与I/O相关的Qt API使用基于UTF-16的QStrings来表示文件路径。然而,标准C++API(或)或特定于平台的API通常需要8位编码路径。您可以使用encodeName()和解码名称()在这两种表示之间进行转换。
在Unix上,有些特殊的系统文件(例如在/proc中)的size()总是返回0,但您仍然可以从这样的文件中读取更多的数据;数据是直接响应您调用read()而生成的。然而,在这种情况下,您不能使用atEnd()来确定是否有更多的数据要读取(因为对于声称大小为0的文件,atEnd(()将返回true)。相反,您应该反复调用readAll(),或者调用read()或readLine(),直到无法读取更多数据为止。下一个示例使用QTextStream逐行读取/proc/modules:
file = QFile("/proc/modules")
if not file.open(QIODevice.ReadOnly | QIODevice.Text):
return
in = QTextStream(file)
line = in.readLine()
while not line.isNull():
process_line(line)
line = in.readLine()
文件权限在类Unix系统和Windows上的处理方式不同。在类Unix系统上的不可写目录中,无法创建文件。在Windows上并不总是这样,例如,"我的文档"目录通常是不可写的,但仍然可以在其中创建文件。
Qt对文件权限的理解是有限的,这尤其影响了setPermissions()函数。在Windows上,Qt将只设置传统的只读标志,并且只有在没有传递Write*标志时才会设置。Qt不操作访问控制列表(ACL),这使得该功能对NTFS卷基本上没有用处。它仍然可以用于使用VFAT文件系统的USB记忆棒。POSIX ACL也没有被操纵。
在Android上,处理内容URI时会有一些限制:
- 通过QFileDialog提示用户可能需要访问权限,该对话框实现了Android的本地文件选择器。
- 旨在遵循Scoped存储指南,例如使用特定于应用程序的目录,而不是其他公共外部目录。有关详细信息,另请参阅存储最佳做法。
- 由于Qt API(例如QFile)的设计,不可能将后一种API与Android的MediaStore API完全集成。
QFile的常用方法
QFile的常用方法如表所示,主要方法介绍如下
-
QFile打开的文件可以在创建实例时输入
- 也可以用setFileName(name:Union[str,bytes,os.PathLike])方法来设置
- 用fileName()方法可以获取文件名。
- 设置文件名后,用open(QIODeviceBase OpenMode)方法打开文件
- 或者用open(fh,QIODevice.OpenMode,handleFlags)方法打开文件;
- 其中fh 是文件句柄号(filehandle),文件句柄号对于打开的文件而言是唯一的识别标识;
- 参数 handleFlags可以取 QFileDevice.AutoCloseHandle(通过 close()来关闭)或 QFileDevice.DontCloseHandle(如果文件没有用close()关闭,当QFile 构后,文件句柄一直打开,这是默认值)。
- 或者用open(fh,QIODevice.OpenMode,handleFlags)方法打开文件;
- 也可以用setFileName(name:Union[str,bytes,os.PathLike])方法来设置
-
QFile 的读取和写入需要使用QIODevice 的方法
-
例如 read(int)、readAlI()readLine()、getChar()、peek(int),write(QByteArray)或 putChar(str)。
-
用setPermissions(permissionSpec: PySide6.QtCore.QFileDevice.Permission)方法设置打开的文件的权限,其中参数QFileDevice.Permission 可以取:
PySide6.QtCore.QFileDevice.Permission(继承enum.Flag)此枚举由permission()函数用于报告文件的权限和所有权。可以将这些值"或"运算在一起,以测试多个权限和所有权值。
Constant Description QFileDevice.ReadOwner 文件的所有者可以读取该文件。 QFileDevice.WriteOwner 文件的所有者可以写入该文件。 QFileDevice.ExeOwner 该文件可由该文件的所有者执行。 QFileDevice.ReadUser 用户可以读取该文件。 QFileDevice.WriteUser 该文件可由用户写入。 QFileDevice.ExeUser 该文件可由用户执行。 QFileDevice.ReadGroup 该文件可由组读取。 QFileDevice.WriteGroup 该文件可由组写入。 QFileDevice.ExeGroup 该文件可由组执行。 QFileDevice.ReadOther 该文件可供其他人阅读。 QFileDevice.WriteOther 该文件可由其他人写入。 QFileDevice.ExeOther 该文件可由其他人执行。 由于Qt支持的平台不同,ReadUser、WriteUser和ExeUser的语义取决于平台:在Unix上,返回文件所有者的权限,在Windows上返回当前用户的权限。这种行为可能会在未来的Qt版本中发生变化。
-
-
用QFile 的静态函数可以对打开的文件或没有打开的文件进行简单的管理
- 用exists()方法判断打开的文件是否存在
- 用exists(fileName)方法判断其他文件是否存在
- 用copy(newName)方法可以把打开的文件复制到新文件中
- 用copy(fileName,newName)方法可以把其他文件复制到新文件中
- 用remove()方法可以移除打开的文件
- 用remove(fileName)方法可以移除其他文件
- 用rename(newName)方法可以对打开的文件重命名
- 用rename(oldName;newName)方法可以对其他文件重命名
QFile的方法及参数类型 | 返回数据类型 | 说 明 |
---|---|---|
copy(newName:str) | bool | 将名为fileName()的文件复制到newName。 此文件在复制之前已关闭。 如果复制的文件是符号链接(symlink),则复制它所引用的文件,而不是链接本身。除了复制的权限外,不会复制其他文件元数据。 如果成功,则返回true;否则返回false。 请注意,如果名为newName的文件已经存在,则copy()将返回false。这意味着QFile不会覆盖它。 |
exists() | bool | 这是一个重载函数。 如果fileName()指定的文件存在,则返回true;否则返回false。 |
link(fileName:str,newName:str) | bool | 这是一个重载函数。 创建一个名为linkName的链接,该链接指向文件fileName。链接是什么取决于底层文件系统(无论是Windows上的快捷方式还是Unix上的符号链接)。如果成功,则返回true;否则返回false。 |
moveToTrash() | bool | 将fileName()指定的文件移到垃圾桶中。如果成功,则返回true,并将fileName()设置为可以在垃圾桶中找到文件的路径;否则返回false。 |
open(fd: int,ioFlags: PySide6.QtCore.QIODeviceBase.OpenModeFlag,handleFlags: PySide6.QtCore.QFileDevice.FileHandleFlag = Instance(PySide6.QtCore.QFileDevice.FileHandleFlag.DontCloseHandle)) | bool | 这是一个重载函数。 以给定的模式打开现有的文件描述符fd。handleFlags可用于指定其他选项。如果成功,则返回true;否则返回false。 当使用此函数打开QFile时,close()的行为由AutoCloseHandle标志控制。如果指定了AutoCloseHandle,并且此函数成功,那么调用close()将关闭所采用的句柄。否则,close()实际上不会关闭文件,而只是刷新它。 如果fd不是常规文件,例如,它是0(stdin)、1(stdout)或2(stderr),则您可能无法查看k()。在这些情况下,size()返回0。有关详细信息,请参见isSequential()。 由于此函数在不指定文件名的情况下打开文件,因此不能将此QFile与QFileInfo一起使用。 |
open(flags: PySide6.QtCore.QIODeviceBase.OpenModeFlag) | bool | 同上 |
open(flags: PySide6.QtCore.QIODeviceBase.OpenModeFlag,permissions: PySide6.QtCore.QFileDevice.Permission) | bool | 这是一个重载函数。 如果该文件不存在,并且模式意味着要创建该文件,则会使用指定的权限创建该文件。在POSIX系统上,实际权限受到umask值的影响。 在Windows上,使用ACL模拟权限。当组被授予的权限比其他组少时,这些ACL可能处于非规范顺序。当"属性"对话框的"安全"选项卡打开时,具有此类权限的文件和目录将生成警告。向组授予授予其他人的所有权限可以避免此类警告。 |
remove() | bool | 删除fileName()指定的文件。如果成功,则返回true;否则返回false。 文件在删除之前已关闭。 |
rename(newName:str) | bool | 将fileName()当前指定的文件重命名为newName。如果成功,则返回true;否则返回false。 如果名为newName的文件已经存在,rename()将返回false(即QFile不会覆盖它)。 文件在重命名之前已关闭。 如果重命名操作失败,Qt将尝试将此文件的内容复制到newName,然后删除此文件,只保留newName。如果复制操作失败或无法删除此文件,则会删除目标文件newName以恢复旧状态。 |
setFileName(name:str) | 设置文件的名称。名称可以没有路径、相对路径或绝对路径。 如果文件已经打开,请不要调用此函数。 如果文件名没有路径或相对路径,则使用的路径将是open()**调用时应用程序的当前目录路径。 例子: file = QFile() QDir.setCurrent(“/tmp”) file.setFileName(“readme.txt”) QDir.setCurrent(“/home”) file.open(QIODevice.ReadOnly)# opens"/home/readme.txt"under Unix 请注意,目录分隔符"/"适用于Qt支持的所有操作系统。 | |
symLinkTarget() | str | 这是一个重载函数。 返回符号链接(或Windows上的快捷方式)指向的文件或目录的绝对路径,如果对象不是符号链接,则返回空字符串。 此名称可能不代表现有文件;它只是一根绳子。如果符号链接指向现有文件,exists()将返回true。 |
[Static]setPermissions(filename:str,permissionSpec: PySide6.QtCore.QFileDevice.Permission) | bool | 这是一个重载函数。 将fileName文件的权限设置为权限。 |
[Static]symLinkTarget() | str | 这是一个重载函数。 返回符号链接(或Windows上的快捷方式)指向的文件或目录的绝对路径,如果对象不是符号链接,则返回空字符串。 此名称可能不代表现有文件;它只是一根绳子。如果符号链接指向现有文件,exists()将返回true。 |
[Static]resize(filename:str,sz:int) | bool | 这是一个重载函数。 将fileName设置为size(以字节为单位)sz。如果调整大小成功,则返回true;否则为false。如果sz大于fileName当前为,则新字节将设置为0,如果sz较小,则文件将被截断。 |
[Static]rename(newName:str) | bool | 将fileName()当前指定的文件重命名为newName。如果成功,则返回true;否则返回false。 如果名为newName的文件已经存在,rename()将返回false(即QFile不会覆盖它)。 文件在重命名之前已关闭。 如果重命名操作失败,Qt将尝试将此文件的内容复制到newName,然后删除此文件,只保留newName。如果复制操作失败或无法删除此文件,则会删除目标文件newName以恢复旧状态。 |
[Static]remove() | bool | 删除fileName()指定的文件。如果成功,则返回true;否则返回false。 文件在删除之前已关闭。 |
[Static]permissions(filename:str) | QFileDevice.Permission | 这是一个重载函数。 返回fileName的QFile::Permission的完整OR组合。 |
[Static]moveToTrash() | bool | 将fileName()指定的文件移到垃圾桶中。如果成功,则返回true,并将fileName()设置为可以在垃圾桶中找到文件的路径;否则返回false。 在系统API不报告文件在垃圾桶中的位置的系统上,文件移动后,fileName()将设置为空字符串。在没有垃圾桶的系统上,此函数总是返回false。 |
[Static]link(fileName:str,newName:str) | bool | 这是一个重载函数。 创建一个名为linkName的链接,该链接指向文件fileName。链接是什么取决于底层文件系统(无论是Windows上的快捷方式还是Unix上的符号链接)。如果成功,则返回true;否则返回false。 |
[Static]exists() | bool | 这是一个重载函数。 如果fileName()指定的文件存在,则返回true;否则返回false。 |
[Static]encodeName(fileName:str) | PySide6.QtCore.QByteArray | 将fileName转换为可在本机API中使用的8位编码。在Windows上,编码是来自活动Windows(ANSI)代码页的编码。在其他平台上,这是UTF-8,用于分解形式(NFD)的macOS。 |
[Static]decodeName(localFileName:PySide6.QtCore.QByteArray) | str | 这与使用localFileName的encodeName()相反。 |
[Static]decodeName(localFileName:str) | str | 这是一个重载函数。 返回给定localFileName的Unicode版本。有关详细信息,请参阅encodeName()。 |
[Static]copy(newName:str) | bool | 将名为fileName()的文件复制到newName。 此文件在复制之前已关闭。 如果复制的文件是符号链接(symlink),则复制它所引用的文件,而不是链接本身。除了复制的权限外,不会复制其他文件元数据。 如果成功,则返回true;否则返回false。 请注意,如果名为newName的文件已经存在,则copy()将返回false。这意味着QFile不会覆盖它。 在Android上,内容方案URI还不支持此操作。 |
QFile的应用实例
下面的程序通过菜单,利用QFile文件可以打开文本文件或十六进制编码文件*hex也可以保存文本文件或十六进制编码文件。
本程序打开的十六进制编码文件是由本程序保存后的十六进制编码文件,不能打开其他程序生成的十六进制编码文件。
程序中可以把打开文本文件和十六进制编码文件的代码放到一个函数中,根据文件扩展名来决定打开哪种格式的文件,保存文件也可以作同样的处理,这里分开到不同动作的槽函数中分别打开文本文件和十六进制文件。
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/10 22:57
# File_name: 01-QFile的应用实例.py
from PySide6.QtWidgets import QApplication,QMainWindow,QPlainTextEdit,QFileDialog
from PySide6.QtCore import QFile,QByteArray
import sys
class MyWindow(QMainWindow):
def __init__(self,parent=None):
super().__init__(parent)
self.resize(800,600)
self.setupUI()# 界面
def setupUI(self): # 界面建立
self.plainText = QPlainTextEdit()
self.setCentralWidget(self.plainText)
self.status = self.statusBar()
self.menubar = self.menuBar()# 文件菜单
self.file = self.menubar.addMenu("文件")# 菜单栏
action_textOpen = self.file.addAction("打开文本文件")# 动作
action_textOpen.triggered.connect(self.textOpen_triggered)# 动作与槽的连
action_dataOpen = self.file.addAction("打开十六进制文件")
action_dataOpen.triggered.connect(self.dataOpen_triggered)
self.file.addSeparator()
action_textWrite = self.file.addAction("保存到新文本文件中")
action_textWrite.triggered.connect(self.textWrite_triggered)
action_dataWrite = self.file.addAction("保存到十六进制文件")
action_dataWrite.triggered.connect(self.dataWrite_triggered)
self.file.addSeparator()
action_close = self.file.addAction("关闭")
action_close.triggered.connect(self.close)
def textOpen_triggered(self):
fileName,file = QFileDialog.getOpenFileName(self,caption="打开文本文件",filter="text(*.txt);;python(*.py);;所有文件(*.*)")
file = QFile(fileName)
if file.exists():
file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text)# 打开文件
self.plainText.clear()
try:
while not file.atEnd():
string = file.readLine()# 按行读取
string = str(string,encoding="utf-8")# 转成字符串
self.plainText.appendPlainText(string.rstrip('\n'))
except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")
file.close()
def textWrite_triggered(self):
fileName,file = QFileDialog.getSaveFileName(self,caption="另存为",filter="text(*.txt);;python(*.py);;所有文件(*.*)")
string = self.plainText.toPlainText()
if fileName !=""and string !="":
ba = QByteArray(string)
file = QFile(fileName)
try:
file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text)# 打开文件
file.write(ba)
except:
self.status.showMessage("文件保存失败!")
else:
self.status.showMessage("文件保存成功!")
file.close()
def dataOpen_triggered(self):
fileName,file = QFileDialog.getOpenFileName(self,caption="打开Hex文件",filter="Hex文件(*.hex);;所有文件(*.*)")
file = QFile(fileName)
if file.exists():
file.open(QFile.OpenModeFlag.ReadOnly)# 打开文件
self.plainText.clear()
try:
while not file.atEnd():
string = file.readLine()# 按行读取数据
string = QByteArray.fromHex(string)# 从十六进制数据中解码
string = str(string,encoding="utf-8")# 从字节转成字符串
self.plainText.appendPlainText(string)
except:
self.status.showMessage("打开文件失败!")
else:
self.status.showMessage("打开文件成功!")
def dataWrite_triggered(self):
fileName,file = QFileDialog.getSaveFileName(self,caption="另存为Hex文件",filter="Hex文件(*.hex);;所有文件(*.*)")
string = self.plainText.toPlainText()
if fileName !=""and string !="":
ba = QByteArray(string)
hex_ba = ba.toHex()
file = QFile(fileName)
try:
file.open(QFile.OpenModeFlag.WriteOnly)# 打开文件
file.write(hex_ba)
except:
self.status.showMessage("文件保存失败!")
else:
self.status.showMessage("文件保存成功!")
file.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec())