98-Data reading and writing and file management-data reading and writing basic class-file QFile

File QFile

QFile inherits from QIODevice and will inherit the methods of QIODevice,

QFile can read and write text files and binary files, and can be used alone or together with QTextStream and QDataStream.

The method of creating an instance object with the QFile class is as follows, where parent is an instance inherited from QObject, and str is the file to be opened. It should be noted that the separator in the file path can be /, // instead of \

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

Description of QFile

QFile is an I/O device for reading and writing text, binary files and resources. QFile can be used by itself, or more conveniently, with QTextStream or QDataStream.

The filename is usually passed in the constructor, but can be set at any time with setFileName(). QFile requires the file separator to be “/”, regardless of the operating system. Other delimiters (such as “”) are not supported.

You can check for the existence of a file with exists() and remove a file with remove(). (QFileInfo and QDir provide more advanced file system-related operations.)

The file is opened with open(), closed with close(), and flushed with flush(). Data is usually read and written using QDataStream or QTextStream, but you can also call QIODevice-inherited functions read(), readLine(), readAll(), write(). QFile also inherits getChar(), putChar(), and ungetChar(), which process one character at a time.

The size of the file is returned by size(). You can use pos() to get the current file position, and seek() to move to a new file position. atEnd() will return true if you have reached the end of the file.

Read files directly

The following example reads a text file line by line:

file = QFile("in.txt")
if not file.open(QIODevice.ReadOnly | QIODevice.Text):
    return
while not file. atEnd():
    line = file. readLine()
    process_line(line)

The QIODevice::Text flag passed to open() tells Qt to convert Windows-style line terminators (“\r\\
“) to C++-style line terminators (“\\
“). By default, QFile is in binary, i.e. no conversion is performed on the bytes stored in the file.

Using streams to read files

The next example reads a text file line by line using 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 is responsible for converting 8-bit data stored on disk into 16-bit Unicode QString. By default, it assumes the file is encoded in UTF-8. This can be changed using setEncoding().

To write text, we can use the operator <<() , which is overloaded to get a QTextStream on the left and various data types (including QString ) on the right:

file = QFile("out.txt")
if not file.open(QIODevice.WriteOnly | QIODevice.Text):
    return
out = QTextStream(file)
out <<"The magic number is:"<< 49 <<"\\
"

QDataStream is similar to this, you can use the operator << () to write data, and use the operator >> () to read data. See the class documentation for details.

Signal

Unlike other QIODevice implementations (such as QTcpSocket), QFile does not emit aboutToClose(), bytesWritten(), or readyRead() signals. This implementation detail means that QFile is not suitable for reading and writing certain types of files, such as device files on Unix platforms.

Platform specific issues

The Qt API related to I/O uses UTF-16 based QStrings to represent file paths. However, standard C++ APIs (or) or platform-specific APIs usually require 8-bit encoding paths. You can convert between these two representations using encodeName() and decodeName().

On Unix, size() always returns 0 for some special system files (such as in /proc), but you can still read more data from such files; the data is directly in response to your call to read() And generated. In this case, however, you cannot use atEnd() to determine if there is more data to read (since atEnd(() will return true for a file with a claimed size of 0). Instead, you should repeatedly call readAll(), or call read() or readLine(), until no more data can be read. The next example uses a QTextStream to read /proc/modules line by line:

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()

File permissions are handled differently on Unix-like systems and Windows. A file cannot be created in a non-writable directory on Unix-like systems. This is not always the case on Windows, for example the “My Documents” directory is usually not writable, but files can still be created in it.

Qt’s understanding of file permissions is limited, which affects the setPermissions() function in particular. On Windows, Qt will only set the traditional read-only flags, and only if no Write* flags are passed. Qt doesn’t manipulate access control lists (ACLs), which makes this feature basically useless for NTFS volumes. It can still be used on USB sticks that use the VFAT file system. POSIX ACLs are not manipulated either.

On Android, there are some limitations when dealing with content URIs:

  • Prompt the user that access permissions may be required through QFileDialog, which implements Android’s native file selector.
  • Designed to follow Scoped storage guidelines, such as using application-specific directories instead of other public external directories. See also storage best practices for details.
  • Due to the design of Qt APIs (e.g. QFile), it is not possible to fully integrate the latter API with Android’s MediaStore API.

Common methods of QFile

The common methods of QFile are shown in the table, and the main methods are introduced as follows

  • Files opened by QFile can be entered when creating an instance

    • You can also use the setFileName(name:Union[str,bytes,os.PathLike]) method to set
      • The file name can be obtained with the fileName() method.
    • After setting the file name, open the file with the open(QIODeviceBase OpenMode) method
      • Or open the file with the open(fh,QIODevice.OpenMode,handleFlags) method;
        • Where fh is the file handle number (filehandle), and the file handle number is the unique identification for the opened file;
        • The parameter handleFlags can take QFileDevice.AutoCloseHandle (closed by close()) or QFileDevice.DontCloseHandle (if the file is not closed by close(), the file handle will always be open after QFile is constructed, which is the default value).
  • The reading and writing of QFile needs to use the method of QIODevice

    • For example read(int), readAlI(), readLine(), getChar(), peek(int), write(QByteArray) or putChar(str).

    • Use the setPermissions(permissionSpec: PySide6.QtCore.QFileDevice.Permission) method to set the permission of the opened file, where the parameter QFileDevice.Permission can be taken as:

      PySide6.QtCore.QFileDevice.Permission (inherited from enum.Flag) This enumeration is used by the permission() function to report permissions and ownership of a file. These values can be “or”operated together to test multiple permission and ownership values.

      Constant Description
      QFileDevice.ReadOwner The owner of the file can read the file.
      QFileDevice.WriteOwner The owner of the file can write to the file.
      QFileDevice.ExeOwner The file can be executed by the owner of the file.
      QFileDevice.ReadUser The user can read the file.
      QFileDevice.WriteUser The file can be written by the user.
      QFileDevice.ExeUser This file can be executed by the user.
      QFileDevice.ReadGroup The file can be read by the group.
      QFileDevice.WriteGroup The file can be written by the group.
      QFileDevice.ExeGroup This file can be executed by the group.
      QFileDevice.ReadOther This file can be read by others.
      QFileDevice.WriteOther This file can be written by others.
      QFileDevice.ExeOther This file can be executed by others.

      Due to the different platforms supported by Qt, the semantics of ReadUser, WriteUser, and ExeUser depend on the platform: on Unix, the permissions of the file owner are returned, and on Windows, the permissions of the current user are returned. This behavior may change in future Qt releases.

  • The static function of QFile can be used for simple management of opened files or unopened files

    • Use the exists() method to determine whether the opened file exists
    • Use the exists(fileName) method to determine whether other files exist
    • Use the copy(newName) method to copy an open file to a new file
    • Use the copy(fileName, newName) method to copy other files to the new file
    • Use the remove() method to remove an open file
    • Use the remove(fileName) method to remove other files
    • Use the rename(newName) method to rename an open file
    • Use the rename(oldName;newName) method to rename other files
QFile method and parameter type return data type description
copy(newName:str) bool Copy the file named fileName() to newName.
This file was closed before copying.
If the copied file is a symbolic link (symlink), the file it refers to is copied, not the link itself. Apart from copied permissions, no other file metadata is copied.
Returns true if successful; otherwise returns false.
Note that copy() will return false if a file named newName already exists. That means QFile won’t overwrite it.
exists() bool This is an overloaded function.
Returns true if the file specified by fileName() exists; otherwise returns false.
link(fileName:str,newName:str) bool This is an overloaded function.
Create a link named linkName that points to the file fileName. What the link is depends on the underlying filesystem (whether it’s a shortcut on Windows or a symbolic link on Unix). Returns true if successful; otherwise returns false.
moveToTrash() bool Move the file specified by fileName() to the trash can. If successful, returns true and sets fileName() to the path where the file can be found in the trash; otherwise returns false.
open(fd: int,ioFlags: PySide6.QtCore.QIODeviceBase.OpenModeFlag,handleFlags: PySide6.QtCore.QFileDevice.FileHandleFlag = Instance(PySide6.QtCore.QFileDevice.FileHandleFlag. DontCloseHandle)) bool This is an overloaded function.
Open an existing file descriptor fd with the given mode. handleFlags can be used to specify additional options. Returns true if successful; otherwise returns false.
When using this function to open a QFile, the behavior of close() is controlled by the AutoCloseHandle flag. If AutoCloseHandle is specified, and this function succeeds, then calling close() will close the handle that was taken. Otherwise, close() doesn’t actually close the file, it just flushes it.
If fd is not a regular file, e.g. it is 0(stdin), 1(stdout) or 2(stderr), you may not be able to see k(). In these cases, size() returns 0. See isSequential() for details.
Since this function opens a file without specifying a filename, you cannot use this QFile with QFileInfo.
open(flags: PySide6.QtCore.QIODeviceBase.OpenModeFlag) bool Ibid
open(flags: PySide6.QtCore.QIODeviceBase.OpenModeFlag,permissions: PySide6.QtCore.QFileDevice.Permission) bool This is an overloaded function.
If the file does not exist, and the mode implies that the file be created, the file is created with the specified permissions. On POSIX systems, actual permissions are affected by the umask value.
On Windows, use ACLs to simulate permissions. These ACLs may be in a non-canonical order when groups are granted fewer permissions than other groups. Files and directories with such permissions will generate a warning when the “Security” tab of the “Properties” dialog is open. Granting the group all permissions granted to others avoids such warnings.
remove() bool Delete the file specified by fileName(). Returns true if successful; otherwise returns false.
The file was closed before deletion.
rename(newName:str) bool Rename the file currently specified by fileName() to newName. Returns true if successful; otherwise returns false.
If a file named newName already exists, rename() will return false (ie QFile will not overwrite it).
The file was closed before being renamed.
If the rename operation fails, Qt will try to copy the content of this file to newName, then delete this file, leaving only newName. If the copy operation fails or the file cannot be deleted, the target file newName is deleted to restore the old state.
setFileName(name:str) Set the name of the file. A name can have no path, a relative path, or an absolute path.
Do not call this function if the file is already open.
If the filename does not have a path or a relative path, the path used will be the current directory path of the application at the time of the open() call.
example:
file = QFile()
QDir.setCurrent(“/tmp”)
file.setFileName(“readme.txt”)
QDir.setCurrent(“/home”)
file.open(QIODevice.ReadOnly)# opens”/home/readme.txt”under Unix
Note that the directory separator “/” works on all operating systems supported by Qt.
symLinkTarget() str This is an overloaded function.
Returns the absolute path to the file or directory pointed to by a symbolic link (or shortcut on Windows), or an empty string if the object is not a symbolic link.
This name may not represent an existing file; it’s just a string. exists() will return true if the symbolic link points to an existing file.
[Static]setPermissions(filename:str,permissionSpec: PySide6.QtCore.QFileDevice.Permission) bool This is An overloaded function.
Set the permissions of the file fileName to permissions.
[Static]symLinkTarget() str This is an overloaded function.
Returns the absolute path to the file or directory pointed to by a symbolic link (or shortcut on Windows), or an empty string if the object is not a symbolic link.
This name may not represent an existing file; it’s just a string. exists() will return true if the symbolic link points to an existing file.
[Static]resize(filename:str,sz:int) bool This is an overloaded function.
Set fileName to size (in bytes) sz. Returns true if the resize was successful; otherwise, false. If sz is larger than fileName is currently, the new bytes will be set to 0, if sz is smaller, the file will be truncated.
[Static]rename(newName:str) bool Rename the file currently specified by fileName() to newName . Returns true if successful; otherwise returns false.
If a file named newName already exists, rename() will return false (ie QFile will not overwrite it).
The file was closed before being renamed.
If the rename operation fails, Qt will try to copy the content of this file to newName, then delete this file, leaving only newName. If the copy operation fails or the file cannot be deleted, the target file newName is deleted to restore the old state.
[Static]remove() bool Delete the file specified by fileName(). Returns true if successful; otherwise returns false.
The file was closed before deletion.
[Static]permissions(filename:str) QFileDevice.Permission This is an overloaded function.
Returns the full OR combination of QFile::Permission for fileName.
[Static]moveToTrash() bool Move the file specified by fileName() to the trash can. If successful, returns true and sets fileName() to the path where the file can be found in the trash; otherwise returns false.
On systems where the system API does not report the location of the file in the trash, fileName() will be set to the empty string after the file has been moved. On systems without a trash can, this function always returns false.
[Static]link(fileName:str,newName:str) bool This is an overloaded function.
Create a link named linkName that points to the file fileName. What the link is depends on the underlying filesystem (whether it’s a shortcut on Windows or a symbolic link on Unix). Returns true if successful; otherwise returns false.
[Static]exists() bool This is an overloaded function.
Returns true if the file specified by fileName() exists; otherwise returns false.
[Static]encodeName(fileName:str) PySide6.QtCore.QByteArray Convert fileName to the local The 8-bit encoding used in the API. On Windows, the encoding is the encoding from the active Windows (ANSI) code page. On other platforms, this is UTF-8 for macOS in Factorized Form (NFD).
[Static]decodeName(localFileName:PySide6.QtCore.QByteArray) str This is the same as encodeName() using localFileName on the contrary.
[Static]decodeName(localFileName:str) str This is an overloaded function.
Returns the Unicode version of the given localFileName. See encodeName() for details.
[Static]copy(newName:str) bool Copy the file named fileName() to newName.
This file was closed before copying.
If the copied file is a symbolic link (symlink), the file it refers to is copied, not the link itself. Apart from copied permissions, no other file metadata is copied.
Returns true if successful; otherwise returns false.
Note that copy() will return false if a file named newName already exists. That means QFile won’t overwrite it.
On Android, content-scheme URIs do not yet support this.

Application example of QFile

The following programs can open text files or hexadecimal coded files *hex by using QFile files through the menu, and can also save text files or hexadecimal coded files.

The hexadecimal encoded file opened by this program is the hexadecimal encoded file saved by this program, and the hexadecimal encoded file generated by other programs cannot be opened.

In the program, the code for opening text files and hexadecimal encoded files can be put into one function, and the format of the file to be opened is determined according to the file extension, and the same process can be done for saving the file. Open the text file and the hexadecimal file respectively in the slot function.

# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/10 22:57
# File_name: 01-QFile application example.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()# interface

    def setupUI(self): # Interface establishment
        self. plainText = QPlainTextEdit()
        self.setCentralWidget(self.plainText)
        self.status = self.statusBar()
        self.menubar = self.menuBar()# file menu
        self.file = self.menubar.addMenu("file")# menu bar

        action_textOpen = self.file.addAction("Open text file")# action
        action_textOpen.triggered.connect(self.textOpen_triggered)# Action and slot connection

        action_dataOpen = self.file.addAction("Open hexadecimal file")
        action_dataOpen.triggered.connect(self.dataOpen_triggered)

        self. file. addSeparator()

        action_textWrite = self.file.addAction("Save to a new text file")
        action_textWrite.triggered.connect(self.textWrite_triggered)

        action_dataWrite = self.file.addAction("save to hexadecimal file")
        action_dataWrite.triggered.connect(self.dataWrite_triggered)

        self. file. addSeparator()

        action_close = self.file.addAction("close")
        action_close.triggered.connect(self.close)

    def textOpen_triggered(self):
        fileName,file = QFileDialog.getOpenFileName(self,caption="Open text file",filter="text(*.txt);;python(*.py);;all files(*.*)")
        file = QFile(fileName)
        if file. exists():
            file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text)# Open the file
            self. plainText. clear()

            try:
                while not file. atEnd():
                    string = file.readLine()# read by line
                    string = str(string,encoding="utf-8")# convert to string
                    self.plainText.appendPlainText(string.rstrip('\\
'))
            except:
                self.status.showMessage("Failed to open the file!")
            else:
                self.status.showMessage("Open the file successfully!")

        file. close()

    def textWrite_triggered(self):
        fileName,file = QFileDialog.getSaveFileName(self,caption="Save as",filter="text(*.txt);;python(*.py);;all files(*.*)")
        string = self.plainText.toPlainText()

        if fileName !=""and string !="":
            ba = QByteArray(string)
            file = QFile(fileName)

            try:
                file.open(QFile.OpenModeFlag.ReadOnly | QFile.OpenModeFlag.Text)# Open the file
                file. write(ba)
            except:
                self.status.showMessage("Failed to save the file!")
            else:
                self.status.showMessage("File saved successfully!")

            file. close()

    def dataOpen_triggered(self):
        fileName, file = QFileDialog.getOpenFileName(self,caption="Open Hex file", filter="Hex file (*.hex);; all files (*.*)")

        file = QFile(fileName)
        if file. exists():
            file.open(QFile.OpenModeFlag.ReadOnly)# Open the file
            self. plainText. clear()

            try:
                while not file. atEnd():
                    string = file.readLine()# read data by line
                    string = QByteArray.fromHex(string)# Decode from hexadecimal data
                    string = str(string,encoding="utf-8")# convert from byte to string
                    self. plainText. append PlainText(string)
            except:
                self.status.showMessage("Failed to open the file!")
            else:
                self.status.showMessage("Open the file successfully!")

    def dataWrite_triggered(self):
        fileName, file = QFileDialog.getSaveFileName(self,caption="Save as Hex file", filter="Hex file (*.hex);; all files (*.*)")

        string = self.plainText.toPlainText()
        if fileName !=""and string !="":
            ba = QByteArray(string)
            hex_ba = ba.toHex()
            file = QFile(fileName)

            try:
                file.open(QFile.OpenModeFlag.WriteOnly)# Open the file
                file.write(hex_ba)
            except:
                self.status.showMessage("Failed to save the file!")
            else:
                self.status.showMessage("File saved successfully!")

            file. close()


if __name__ == '__main__':
    app = QApplication(sys. argv)
    win = MyWindow()

    win. show()
    sys. exit(app. exec())