关闭

Essential Qt 第十二章 文本文件的读写

205人阅读 评论(0) 收藏 举报
分类:
                在C/C++语言中,有一大堆关于本地文件读写的函数,比如C语言提供了至少30个以上的IO函数来支持文件的读写,而C++则使用fstream等类来完成,当然关于C++的IO相关部分足可以写出好几部大头书。在Qt中也提供了很多和文件读写相关的IO类,这里只能简单的介绍其中的一小部分。关于文件,window下区分文本文件和二进制文件,而linux下则不做区分,而Qt为了则提供了QTextStream和QDateStream两个类,分别用于文本文件和二进制文件的IO,这一章简单介绍下QTextStream类,这样可以完成前面ReadMe程序中“文件”菜单上的功能。
                在Qt中提供了和文件相关的类QFile,这个类用于文件的操作,另外还有一个类QFileInfo则提供了大量和文件相关成员函数,比如path()函数用于返回文件路径,isDir()返回该文件(名)是否问目录,isFile()则返回是否问文件,等等
                回到QFile类,对于这个类来说,用来创建一个新文件很简单
QFile F(FilePath);
F.open(QIODevice::ReadWrite);//注释1
F.close();//注释2
注释1: 这里使用了成员函数open()来打开一个文件,参数是文件打开的方式,如果熟悉C语言的fopen()函数,类似与参数r,r+w,w等,该枚举值QIODevice::OpenModeFlag在QIODevice中定义
注释2: 这里使用了close()函数来关闭打开的文件,一般来说Qt的QFile类操作文件不需要来调用这个close()函数,QFile对象在离开作用域后会自动关闭,但比较特殊的是创建文件,Qt创建文件的方法有些“特别”,如上所示,先打开一个文件,然后再显式的关闭,这样就创建了一个新文件,当然前提是确保上面的FilePath不存在,如果需确认,可以先调用exist()函数确定这个文件是否已经存在
                  文本文件的IO需要用到QTextStream类,下面的代码是向一个文件写数据
QFile F(FilePath);
QTextStream FDate(&F);  //注释1
F.open(QIODevice::WriteOnly);
FDate<<"This is Qt.";  //注释2
注释1:这里生成了一个“文本文件的流”,这是我起的名字,因为我找不到更合适的词汇来称呼他,(只写)打开文件后,可以对这个流进行写操作,这里将"This is Qt"写入流,从而达到写入文件的目的
注释2: 这里QTextStream使用操作符"<<"来进行数据输入,这个C++的iostream类很相似,如果要读取文本文件也很简单,只需要打开文件是的参数使用读,然后用">>"把数据读到相应的对象里即可,QTextStream类还提供了一些函数来用于对数据的读写readLine()用于逐行读取文件的内容,readAll()则用于把文件的内容一次性读取等

               接下来我们将完成前面ReadMe文件中尚未完成的“文件”菜单功能。首先是“打开”功能,在ReadMe.h中添加一个私有槽void OpenExistFile()来实现这个功能,该槽函数具体实现如下
void ReadMe::OpenExistFile()
{
  CurrentFilePath = QFileDialog::getOpenFileName(this,tr("打开文件"),".",tr("Text(*.txt)"));//注释1
  if(CurrentFilePath.isEmpty())  //注释2
  {
    QMessageBox::warning(this,tr("空文件"),tr("该文件为空或不存在"),QMessageBox::Yes);
    return;
  }
  QFile F(CurrentFilePath);
  QTextStream FDate(&F);
  F.open(QIODevice::ReadWrite|QIODevice::Text);
  MainEditWindow->setText(FDate.readAll()); //注释3
}
注释1: 变量CurrentFilePath在ReadMe.h中定义的一个QString对象,这个对于用于保持当前编辑的文本的(包含完成路径)文件名。这里使用了QFileDialog的静态函数来打开一个文件,这个函数会创建一个以来本地系统的文件打开对话框,使用的第一个参数为该对话框的父对象,第二个参数为对话框标题,第三个参数为对话框出现的默认路径,这里使用"."来表示(程序的)当前目录,如果希望使用其他目录作为默认目录,则可以用一个QString来替换这个".".第四个参数是这个对话框需要打开的文件类型,基本格式为 文件类型(*.文件后缀),以这个例子为例,如果你还希望他能打开.cxx和.cpp的文本文件,则第四个参数可以写出tr(Text(*.txt*.cpp*.cxx);这个函数返回值是打开的文件,包含完成路径名的文件名,类型为QString,如果用户在对话框中点击取消或者之间点击"X"关闭了对话框,则该函数返回一个空的QString,
注释2: 用过判断文件名是否为空可以知道用户有没有打开文件
注释3: 这里使用了上面的利用QTextStream类来读取文件的信息,成员函数readAll()会把文件所有内容都读取到内存中,由于纯文本文件一般都比较小,所以不会有什么问题,但如果是其他类型的数据,使用readAll()就要慎重考虑内存的大小。

           然后是“保存”功能具体实现为
void ReadMe::SaveCurrentFile()
{
  if(CurrentFilePath.isEmpty())  //注释1
    SaveAsCurrentFile();
  else
  {
    QFile F(CurrentFilePath);
    QTextStream FDate(&F);
    F.open(QIODevice::WriteOnly);
    FDate<<(MainEditWindow->toPlainText());  //注释2
    MainEditWindow->document()->setModified(false);  //注释3
  }
}
注释1: 这里有个特殊情况需要考虑,第一次打开程序,然后输入了诺干字符,此时由于没有打开任何文件,所欲用于保存当前编辑文件名的变量此时为空,出现这种情况是点击保存则必须使用“另存为”的功能,“另存为”稍后实现
注释2: 这里使用QTextStream来实现文件的写功能      
注释3: QTextEdit的成员函数document()将编辑的内容作为一个QDocument类来返回,这个类提供了很多和文本相关的函数,其中setModified()函数可以将设置文本没有过改动,或者有过改动,在这个例子中,文件保存后就将编辑的文本设置为“未改动”状态。而函数isModified()函数则返回文本有无改动   

          然后是"另存为"功能实现
void ReadMe::SaveAsCurrentFile()
{
  CurrentFilePath = QFileDialog::getSaveFileName(this,tr("文件另存为"),".",tr("Text(*.txt)"));//注释1
  if(CurrentFilePath.isEmpty()) //注释2
  {
    QMessageBox::warning(this,tr("保存失败"),tr("保存文件失败"),QMessageBox::Yes);
    return;
  }
  QFile F(CurrentFilePath);
  QTextStream FDate(&F);
  F.open(QIODevice::WriteOnly);
  FDate<<(MainEditWindow->toPlainText());
  MainEditWindow->document()->setModified(false);//注释3
}
注释1: 这里使用了QFileDialog的另一个静态函数,该函数生产一个以来本地系统的保存文件对话框,函数的参数和返回值和打开功能中的QFileDialog::getOpenFileName()函数一样
注释2: 这里同样需要判断下保存文件对话框有没有选取到正确的文件,用户点击取消或直接关闭对话框同样会返回空值
注释3: 在另存为文件,再次调用setModified()函数将文本设置为“未改动”

              最后是稍显复杂的“新建”功能
void ReadMe::CreateNewFile()
{
  if(MainEditWindow->document()->isModified() and !(MainEditWindow->toPlainText().isEmpty())) //注释1
  {
    int buttons = QMessageBox::warning(this,tr("文件未保存"),tr("原文件尚未保存,是否需要保存?"),QMessageBox::Yes|QMessageBox::No);
    if(buttons == QMessageBox::Yes)
    {
      if(CurrentFilePath.isEmpty()) //注释2
        SaveAsCurrentFile();
      else
        SaveCurrentFile();
    }
    if(buttons == QMessageBox::No)  //注释3
       MainEditWindow->clear();
  }
  if(CurrentFilePath.isEmpty()) //注释4
    return;
  MainEditWindow->clear();
}
注释1:在新建一个文件之前,需要判断下这个编辑窗体中是否有文本,以及文本有没有改动,如果窗体中存在文本,且文本状态为“已经改动”,则需要提示用户是否需要保存当前编辑的文本
注释2 :如果需要保存,这里还要区分两种情况,即如果正在编辑的文本是第一次打开程序后写入的内容,此时程序中用于保持文件名的变量CurrentFilePath为空,遇到这种情况需要使用“另存为”来保存文本,其他情况则使用“保持”
注释3: 如果用户选择了不需要保存,则直接清空编辑框里的内容
注释4: 这行代码用于应对一种特殊情况,在注释2中,用户选择了保存文件,而且这个文件是第一次打开程序输入的文件(即CurrentFilePath为空),然后转至"另存为"中,但在“另存为”函数中,用户没有保存,而是直接关闭了文件保存对话框,遇到这种情况,就必须避免用户在“另存为”功能中选择不保存而把编辑的内容清空掉

               最后把这些槽函数和对应的“文件”菜单中的动作连接起来,在ConnectSignalAndSlot()函数中添加
  connect(Open_Action,SIGNAL(triggered()),this,SLOT(OpenExistFile()));
  connect(New_Action,SIGNAL(triggered()),this,SLOT(CreateNewFile()));
  connect(Save_Action,SIGNAL(triggered()),this,SLOT(SaveCurrentFile()));
  connect(SaveAs_Action,SIGNAL(triggered()),this,SLOT(SaveAsCurrentFile()));


               就ReadMe程序,要完善他的功能,还需要重新实现它的关闭事件函数,在关闭事件之前,首先要用isModified()判断当前编辑文本是否已经被保存,如果没有保存,则需要询问下是否需要被保存,这里和“新建”功能有些类似
               
void ReadMe::closeEvent(QCloseEvent* event)
{
  if(MainEditWindow->document()->isModified() and !(MainEditWindow->toPlainText().isEmpty()))
  {
    int buttons = QMessageBox::warning(this,tr("文件未保存"),tr("原文件尚未保存,是否需要保存?"),QMessageBox::Yes|QMessageBox::No);
    if(buttons == QMessageBox::Yes)
    {
      if(CurrentFilePath.isEmpty())
        SaveAsCurrentFile();
      else
        SaveCurrentFile();
      event->ignore();    //注释1
    }
    if(buttons == QMessageBox::No)
    {
      event->accept();    
      return;
    }
  }
}
注释1: 对于一个为编辑的文本,程序在关闭前给出了一个提示,是否需要保存,如果选择了保存,则进入保存程序,但无论用户是否保存,这次关闭事件都将不执行,这里用事件的成员函数igrone()来屏蔽掉此次关闭事件
    


0
0
查看评论

QT 读取txt 文件

今天学习QT的文件操作   1、QIODevice 直接继承自QObject QIODevice类是输入/输出设备的基类。 QIODevice为设备提供了公共实现和抽象接口用于读写块数据。 QIODevice是一个抽象类,不能被实例化。 被Q3Socket...
  • qq61394323
  • qq61394323
  • 2013-12-10 10:24
  • 24942

QT学习 之 文本文件读写

上一章我们介绍了有关二进制文件的读写。二进制文件比较小巧,却不是人可读的格式。而文本文件是一种人可读的文件。为了操作这种文件,我们需要使用QTextStream类。QTextStream和QDataStream的使用类似,只不过它是操作纯文本文件的。另外,像 XML、HTML 这种,虽然也是文本文件...
  • u013007900
  • u013007900
  • 2015-06-11 17:07
  • 2856

Qt中文本文件的读写

1.简介Qt中的文本晚间读写方式很多,但是对于我这种初学者而言,贪多嚼不烂,所以只总结一下QTextStream类的读写接口;2.代码片段//写文件 QFile file("data.txt"); //如果data.txt不存在,那么将会创建,如果不指定路径,对于Qt而言,默认在...
  • wdl20170204
  • wdl20170204
  • 2017-03-01 15:15
  • 177

QT读写csv文件(文本文件)

//写文件void MainWindow::on_pushButton_clicked() { if(dataMap.size()<=0){ QMessageBox::information(this,"","请先进行读数据操作!"...
  • u013776188
  • u013776188
  • 2017-11-23 15:42
  • 272

VB.NET读写文本文件方法

 作者:ll_efort      发布时间:2008-08-11 09:00:24      来源:网络工作需要,小编需要使用vb.net对文本文件进行读写操作。编程需...
  • lsh2216024
  • lsh2216024
  • 2008-12-24 15:44
  • 3504

android 私有文件夹、文件的写入与读取

在介绍如何在Android平台下进行文件的读取之前,有必要了解Android平台下的数据存储规则。在其他的操作系统如Windows 平台下,应用程序可以自由地或者在特定的访问权限基础上访问或修改其他应用程序名下的文件等资源,而在Android平台下,一个应用程序中所有的数据都是私有的。 ...
  • rongwenbin
  • rongwenbin
  • 2014-09-28 14:24
  • 454

《Essential C++》读书笔记

最近想复习一下C++的知识,刚好实验室有一本《Essential C++》,页数比较平易近人,花了两天过了一遍,做了一些笔记。个人觉得里面举得代码不够浅显(很多都是符号重构),让人没有想看的欲望,
  • huang1433
  • huang1433
  • 2015-10-29 20:47
  • 533

二进制文件及其顺序读写

short int在内存中需要两个字节,而这两个字节就是它的二进制存储形式。 比如short int x=12345; 那么ASCII存储为:00110001  00110010  00110011  00110100  00110101 二进制形式存储为:0...
  • u010141928
  • u010141928
  • 2017-06-13 14:08
  • 354

垃圾《Essential C++》

    看过很多人的介绍和评论之后,我决定购买这本《Essential C++》。最后却看得一头雾水,头都大了几倍。    这是一本什么样的书?“拿起这本书,你可以在短时间内熟悉C++。”我觉得自己很聪明,而且还有其他语言的基础,想想自己应...
  • whycrying
  • whycrying
  • 2006-05-16 19:39
  • 29682

Qt 学习 之 二进制文件读写

在上一章中,我们介绍了有关QFile和QFileInfo两个类的使用。我们提到,QIODevice提供了read()、readLine()等基本的操作。同时,Qt 还提供了更高一级的操作:用于二进制的流QDataStream和用于文本流的QTextStream。本节,我们将讲解有关QDataStre...
  • u013007900
  • u013007900
  • 2015-06-11 16:59
  • 5439
    个人资料
    • 访问:11441次
    • 积分:141
    • 等级:
    • 排名:千里之外
    • 原创:84篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    最新评论
  • 学生管理系统

    qq_20553613: 不错,用txt方式模拟数据库。可以改用MySQL实现,加入搜索等功能;代码量和逻辑容易实现多了。另外...