应用程序操作过程中,经常要对设备或文件进行读或者写操作。也会经常对文件及目录进行操作。
在Qt中,QIODevice类是Qt中所有进行I/O操作的设备的基类,比如QFile、
QIODevice为支持数据块读写的设备(如QFile、QBuffer和QTcpSocket)提供了通用的实现和抽象接口。QIODevice是一个抽象类,不能实例化,但通常可以使用其定义的接口来提供与设备无关的I/O功能。例如,Qt的XML类操作使用QIODevice指针,可以与各种设备(如文件和缓冲区)一起使用。
在访问设备之前,必须调用open()方法设置正确的OpenMode(如ReadOnly或ReadWrite)。然后,可以使用write()或putChar()向设备写入数据,并通过调用read()、readLine()或readAll()来读取数据。完成后调用close()方法关闭设备。
QIODevice区分两种类型的设备:随机访问设备和顺序访问设备。
随机访问设备支持使用seek()方法随机定位到任意位置。通过调用pos()方法可以获取文件中的当前位置。QFile和QBuffer是随机访问设备的示例。
顺序访问设备不支持随机定位到任意位置。数据必须一次性读取。pos()和size()方法对于顺序访问设备无效。QTcpSocket和QProcess是顺序访问设备的示例。
可以使用isSequential()方法来确定设备的类型。
当有新数据可供读取时,QIODevice会发出readyRead()信号;例如,如果网络上有新数据到达或者从正在读取的文件中追加了其他数据。可以调用bytesAvailable()方法来确定当前可供读取的字节数。在使用异步设备(如QTcpSocket)进行编程时,通常将bytesAvailable()与readyRead()信号一起使用,因为数据的片段可能在任意时间点到达。每当写入了一批数据时,QIODevice发出bytesWritten()信号。使用bytesToWrite()方法可以确定当前等待写入的数据量。
QIODevice的某些子类(如QTcpSocket和QProcess)是异步的。这意味着I/O函数(如write()或read())总是立即返回,而与设备本身的通信可能在控制返回到事件循环时发生。QIODevice提供了一些函数,允许强制立即执行这些操作,同时阻塞调用线程而不进入事件循环。这使得QIODevice子类可以在没有事件循环的情况下使用,或者在单独的线程中使用:
waitForReadyRead() - 该函数会在调用线程中暂停操作,直到有新数据可供读取。
waitForBytesWritten() - 该函数会在调用线程中暂停操作,直到写入了一批数据到设备中。
waitFor…() - QIODevice的子类实现了针对特定设备操作的阻塞函数。例如,QProcess有一个名为waitForStarted()的函数,该函数会在调用线程中暂停操作,直到进程启动。
QIODevice中的打开模式:
常量 | 值 | 描述 |
---|---|---|
QIODevice::NotOpen | 0x0000 | 设备未打开。 |
QIODevice::ReadOnly | 0x0001 | 设备已打开用于读取。 |
QIODevice::WriteOnly | 0x0002 | 设备已打开用于写入。请注意,此模式意味着截断。 |
QIODevice::ReadWrite | ReadOnly | WriteOnly |
QIODevice::Append | 0x0004 | 设备以追加模式打开,使得所有数据都写入文件末尾。 |
QIODevice::Truncate | 0x0008 | 如果可能,设备在打开之前被截断。设备中的所有早期内容都将丢失。 |
QIODevice::Text | 0x0010 | 在读取时,行尾终止符被转换为’\n’。在写入时,行尾终止符被转换为本地编码,例如Win32下的’\r\n’。 |
QIODevice::Unbuffered | 0x0020 | 设备中的任何缓冲区都被绕过。 |
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。
如直接使用QFile进行操作:
QFile file("in.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
while (!file.atEnd()) {
QByteArray line = file.readLine();
process_line(line);
}
或搭配QTextStream类进行操作:
QFile file("in.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
process_line(line);
}
进行输出:
QFile file("out.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << "The magic number is: " << 49 << "\n";
QFileInfo类提供了与系统无关的文件信息。
QFileInfo提供了有关文件在文件系统中的名称和位置(路径)、访问权限、是否是目录或符号链接等信息。还可以获取文件的大小和最后修改/读取的时间。QFileInfo还可以用于获取有关Qt资源的信息。
QFileInfo可以指向具有相对或绝对文件路径的文件。绝对文件路径以目录分隔符“/”(在Windows上以驱动器规范开头)开头。相对文件名以目录名称或文件名称开头,并指定相对于当前工作目录的路径。绝对路径的示例是字符串“/tmp/quartz”。相对路径可能看起来像“src/fatlib”。您可以使用isRelative()函数检查QFileInfo是否使用相对或绝对文件路径。您可以调用makeAbsolute()函数将相对QFileInfo的路径转换为绝对路径。
QFileInfo在构造函数中设置要处理的文件,或在后续使用setFile()设置。使用exists()来查看文件是否存在,并使用size()来获取文件的大小。
使用isFile()、isDir()和isSymLink()获取文件的类型。symLinkTarget()函数提供符号链接所指向的文件的名称。
在Unix系统(包括macOS和iOS)上,符号链接的大小()与其指向的文件相同,因为Unix透明地处理符号链接;同样,使用QFile打开符号链接实际上打开了链接的目标。例如:
#ifdef Q_OS_UNIX
QFileInfo info1("/home/bob/bin/untabify");
info1.isSymLink(); // returns true
info1.absoluteFilePath(); // returns "/home/bob/bin/untabify"
info1.size(); // returns 56201
info1.symLinkTarget(); // returns "/opt/pretty++/bin/untabify"
QFileInfo info2(info1.symLinkTarget());
info2.isSymLink(); // returns false
info2.absoluteFilePath(); // returns "/opt/pretty++/bin/untabify"
info2.size(); // returns 56201
#endif
在Windows上,符号链接(快捷方式)是.lnk文件。报告的size()是符号链接的大小(而不是链接的目标),使用QFile打开符号链接会打开.lnk文件。例如:
#ifdef Q_OS_WIN
QFileInfo info1("C:\\Documents and Settings\\Bob\\untabify.lnk");
info1.isSymLink(); // returns true
info1.absoluteFilePath(); // returns "C:/Documents and Settings/Bob/untabify.lnk"
info1.size(); // returns 743
info1.symLinkTarget(); // returns "C:/Pretty++/untabify"
QFileInfo info2(info1.symLinkTarget());
info2.isSymLink(); // returns false
info2.absoluteFilePath(); // returns "C:/Pretty++/untabify"
info2.size(); // returns 63942
#endif
文件名的元素可以使用path()和fileName()提取。可以使用baseName()、suffix()或completeSuffix()提取fileName()的部分。由Qt类创建的目录的QFileInfo对象将不包含尾部的文件分隔符。如果您希望在自己的文件信息对象中使用尾部分隔符,只需将一个追加到构造函数或setFile()给定的文件名中。
文件的日期可以使用created()、lastModified()和lastRead()返回。使用isReadable()、isWritable()和isExecutable()可以获取有关文件访问权限的信息。文件的所有权可以从owner()、ownerId()、group()和groupId()获取。可以使用permission()函数在一个语句中检查文件的权限和所有权。
QTemporaryFile类是一个在临时文件上操作的I/O设备。
QTemporaryFile用于安全地创建唯一的临时文件。文件本身是通过调用open()函数创建的。临时文件的名称是唯一的(即,您不会覆盖现有文件),并且在销毁QTemporaryFile对象时,文件将被自动删除。这是一种重要的技术,可以避免将数据存储在临时文件中的应用程序出现数据损坏。文件名可以是自动生成的,也可以基于传递给QTemporaryFile构造函数的模板创建。
示例:
// Within a function/method...
QTemporaryFile file;
if (file.open()) {
// file.fileName() returns the unique file name
}
// The QTemporaryFile destructor removes the temporary file
// as it goes out of scope.
在调用close()后重新打开QTemporaryFile是安全的。只要QTemporaryFile对象本身没有被销毁,唯一的临时文件将继续存在,并被QTemporaryFile内部保持打开状态。
可以通过调用fileName()找到临时文件的文件名。注意,在文件首次打开之前,此函数返回空字符串。
临时文件的文件名将由一部分静态部分和一部分计算出的唯一部分组成。默认文件名将根据QCoreApplication::applicationName()(否则为qt_temp)确定,并放置在由QDir::tempPath()返回的临时路径中。如果指定了自己的文件名,默认情况下不会将相对文件路径放入临时目录中,而是相对于当前工作目录。
指定的文件名可以包含以下模板"XXXXXX"(六个大写字母"X"字符),该模板将被文件名的自动生成部分替换。请注意,模板是区分大小写的。如果文件名中不存在模板,QTemporaryFile将在给定的文件名后面追加生成的部分。
QTemporaryDir类用于创建一个唯一的临时目录。
QTemporaryDir用于安全地创建唯一的临时目录。目录本身是通过构造函数创建的。临时目录的名称是唯一的(即,您不会覆盖现有目录),并且在销毁QTemporaryDir对象时,目录将被自动删除。目录名可以是自动生成的,也可以基于传递给QTemporaryDir构造函数的模板创建。
示例:
// Within a function/method...
QTemporaryDir dir;
if (dir.isValid()) {
// dir.path() returns the unique directory path
}
// The QTemporaryDir destructor removes the temporary directory
// as it goes out of scope.
非常重要的是使用isValid()来测试临时目录是否能够创建。不要使用exists(),因为默认构造的QDir表示当前目录,该目录存在。
可以通过调用path()来获取临时目录的路径。
临时目录的名称将由一部分静态部分和一部分计算出的唯一部分组成。默认路径将根据QCoreApplication::applicationName()(否则为qt_temp)确定,并放置在由QDir::tempPath()返回的临时路径中。如果指定了自己的路径,默认情况下不会将相对路径放入临时目录中,而是相对于当前工作目录。在所有情况下,将添加一个随机字符串以使路径唯一。
QDir类提供对目录结构及其内容的访问。
QDir用于操作路径名,访问与路径和文件相关的信息,并操作底层文件系统。它还可以用于访问Qt的资源系统。
Qt使用"/“作为通用目录分隔符,就像在URL中使用”/“作为路径分隔符一样。如果您始终使用”/"作为目录分隔符,Qt将根据底层操作系统的规则转换您的路径。
QDir可以使用相对路径或绝对路径指向一个文件。绝对路径以目录分隔符开头(在Windows下可以选择以驱动器规范作为前缀)。相对文件名以目录名或文件名开头,并指定相对于当前目录的路径。
绝对路径的示例:
QDir("/home/user/Documents")
QDir("C:/Documents and Settings")
在Windows上,当用于访问文件时, 上述第二个示例将被转换为"C:\Documents and Settings"。
相对路径的示例:
QDir("images/landscape.png")
您可以使用isRelative()或isAbsolute()函数来检查QDir是否使用相对或绝对文件路径。调用makeAbsolute()将相对的QDir转换为绝对路径。