找回密码
 立即注册
收起左侧

【独家连载】Qt入门与提高: KS04-12 普通文本文件读写

0
回复
6409
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-11-9 14:44:05 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2019-7-2 20:35 编辑

版权声明
---------------------------------------------------------------------------------------------------------------------
该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白
转载请注明出处!
---------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
引言
----------------------------------------------------------------------------------------------------------------------
  在进行软件研发时,文件读写是经常碰到的场景。我们可以用文件来存储配置信息、序列化数据,甚至可以用文件作为接口来交互数据。文件的保存格式一般分为二进制格式和文本格式(也叫ASCII码格式)。我们今天先来看一下文本文件的读写。

正文
----------------------------------------------------------------------------------------------------------------------
   Qt提供了QFile类来处理文件操作,QFile派生自QIODevice。在本节的示例程序中,我们用到了之前章节中的公共类库,以便处理文件路径的解析。
    在示例程序中,然后按照如下过程演示QFile的功能:
    1. 写入一个初始文本文件,
2. 文本文件读取
    3. 文本文件,追加写入
    我们分别来看一下这些示例。
场景1. 写入一个初始文本文件
在本示例中,接口为initialize():
  1. /**
  2.   
  3. * @brief 文本文件初始化
  4.   
  5. *
  6.   
  7. * @return void
  8.   
  9. */
  10.   
  11. void initialize(void)
  12.   
  13. {
  14.   
  15.     QString  strFileName;
  16.   
  17.     strFileName =  ns_train::getPath("$TRAINDEVHOME/test/chapter04/ks04_09/example01.txt");
  18.   
  19. QString strDir =  ns_train::getDirectory(strFileName);
  20.   
  21. QDir dir;
  22.   
  23. dir.mkdir(strDir);
  24.   
  25.   
  26. QFile file(strFileName);
  27.   
  28.   }
复制代码
    为了防止文件路径不存在,我们先用QDir创建目录。
然后我们定义一个QFile对象,并传入文件路径strFileName。这个文件路径通过公共类库中的getPath()接口获得。
    然后,我们设置文件的打开方式:
  1. // 打开方式:只读、文本方式
  2.   
  3.     if (!file.open(QFile::Truncate  | QFile::WriteOnly | QFile::Text)) {
  4.   
  5.         qDebug("open failed!  file name is:%s", strFileName.toLocal8Bit().data());
  6.   
  7.         return;
  8.   
  9.     }
复制代码

    QFile的open接口描述如下:
  1. bool open(OpenMode flags);
复制代码
  其中,OpenMode定义如下:
  1. enum OpenModeFlag {
  2.   
  3.      NotOpen = 0x0000,   // 文件未打开
  4.   
  5.      ReadOnly = 0x0001,  // 以只读方式打开文件,此时对文件调用写入接口会失败。
  6.   
  7.      WriteOnly = 0x0002, // 以只写方式打开文件,此时对文件调用读取接口会失败。
  8.   
  9.      ReadWrite = ReadOnly | WriteOnly, // 以读写方式打开。
  10.   
  11.      Append = 0x0004,    // 以追加方式打开,调用写入接口时,将默认追加到文件末尾。
  12.   
  13.      Truncate = 0x0008,  // 该模式将导致文件打开后被自动清空。
  14.   
  15.      Text = 0x0010,    // 以文本方式打开文件,如果不设置该选项,默认为二进制。
  16.   
  17.      Unbuffered = 0x0020,// 无缓冲方式,慎用。即同步写硬盘,为false则异步写硬盘。
  18.   
  19.      NewOnly = 0x0040,  // 设置该值后,当文件已经存在时,open()返回失败。
  20.   
  21.      ExistingOnly = 0x0080 // 设置该值后,当文件不存在时,open()返回失败。
  22.   
  23. };
  24.   
  25.      Q_DECLARE_FLAGS(OpenMode, OpenModeFlag)
复制代码
    因为我们的接口功能是初始化一个文件,所以使用了QFile::Truncate。
    因为是文本方式写入,所有使用了QFile::Text。
    因为初始化时无需读取,只需写入,所以使用了QFile::WriteOnly。
    然后,我们使用如下代码将strContent写入文件:
  1. if (false) {
  2.   
  3.         file.write(strContent.toLocal8Bit());
  4.   
  5.     }  
  6.   
  7.     else  {
  8.   
  9.         QTextStream  out(&file);
  10.   
  11.         out  << strContent;
  12.   
  13.     }
复制代码
   我们给出两种方案来写入文件,一种是调用write()接口写入文件;另外一种是利用QTextStream流来处理。大家可以把if(false)改为if(true)进行测试。
    在代码最后,一定要记得关闭文件(file.close())。否则就要靠QFile析构时自动关闭,这样可不是友好的编程风格。
场景2. 文本文件读取
本示例代码中,我们用只读方式打开文件:
  1. QFile file(strFileName);
  2.   
  3.     // 打开方式:只读、文本方式
  4.   
  5.     if (!file.open(QFile::ReadOnly  | QFile::Text)) {
  6.   
  7.         qDebug("open failed!  file name is:%s", strFileName.toLocal8Bit().data());
  8.   
  9.         return;
  10.   
  11.     }
  12.   
  13.     // 输出整个文件的内容
  14.   
  15.     QString strContent =  file.readAll();
  16.   
  17.     qDebug("File Opened, this  is the content:\n");
  18.   
  19. qDebug() << strContent;
  20.   
  21. // 将文件游标移到文件开头,否则的话,现在游标已经移动到文件尾,再执行后面的代码将无法读取到内容。
  22.   
  23. file.seek(0);
复制代码
    在上述代码中,我们用readAll()读取整个文件。在此之后,文件游标已经被移动到文件尾,通过seek()接口将文件游标移动到文件开头。
    然后,我们介绍两种按行读取文件的方式(即:一次读取一行,遇到回车换行符就停止)。
    方案1,使用QFile的readLine():
  1. const int c_maxNumber = 10240;
  2.   
  3.         char  buf[c_maxNumber];
  4.   
  5.         qint64  nRead = 0;
  6.   
  7.         qDebug("File  Opened, this is the lines:");
  8.   
  9.         while  (!file.atEnd()) {
  10.   
  11.             nRead  = file.readLine(buf, c_maxNumber);
  12.   
  13.             strContent  = buf;
  14.   
  15.             strContent.remove("\r");
  16.   
  17.             strContent.remove("\n");
  18.   
  19.             qDebug("%s",  strContent.toLocal8Bit().data());
  20.   
  21.         }
复制代码
    通过上述代码可以看出,调用QFile::readLine()需要提供一个足够大的缓冲区并指明最多读取多少个字节,当一行的内容超过c_maxNumber时,即使没有读完整行也会停止读取,因此buf的尺寸和c_maxNumber要根据所要读取的文件内容设置成合适的值。
    方案2,利用QTextStream进行读取:
  1. QTextStream in(&file);
  2.   
  3.     while  (!in.atEnd()) {
  4.   
  5.         QString  line = in.readLine();
  6.   
  7.         qDebug("%s",  line.toLocal8Bit().data());
  8.   
  9.     }
复制代码
  可以看出,使用QTextStream则没有这些限制。我们可以用QString直接存储读到的一行内容。这比方案1要简单多了。
场景3. 文本文件,追加写入
当我们要追加写入时,在打开文件时需要使用QFile::Append:
  1. QFile file(strFileName);
  2.   
  3. // 打开方式:只读、文本方式
  4.   
  5. //if (!file.open(QFile::ReadWrite |  QFile::Text)) {
  6.   
  7. if (!file.open(QFile::ReadWrite |  QFile::Append | QFile::Text)) {
  8.   
  9.     return;
  10.   
  11. }
  12.   
  13. file.seek(0);// 使用QFile::Append打开文件后,游标默认在文件尾。
  14.   
  15. QString strContent =  file.readAll();// readAll()导致文件的游标到达文件尾。
复制代码
    打开文件后,我们调用了seek(0)。原因是使用QFile::Append打开文件后,游标默认在文件尾。如果此时调用QFile::readAll(),将从游标当前位置开始向后读取,但是因为游标已经到文件尾部,所以readAll()将读取不到任何内容。所以我们使用seek(0)将游标移动到文件头。大家可以封掉seek(0),然后比较一下用不同QFile::Append有何不同。
结语
----------------------------------------------------------------------------------------------------------------------
在本节中,我们介绍了通过QFile对文本文件进行操作的基本场景,大家可以练习一下。
如果您希望了解如何在文件开头追加内容、如何对文件进行拷贝、删除、改名、移动等操作,请来支持一下[课程视频] 吧。


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了