目的
我们需要解析DNS配置文件,该文件有时第一行、第二行是DNS地址,有时第三、第四行是DNS地址,并且格式不是完全固定,我们如何从该文件中获取到正确的DNS地址呢?
//第一种
sjdfaljfl
namespace 192.168.1.2
namespace 192.168.1.3
//第二种
namespace 192.168.1.2
namespace 192.168.1.3
//第三种
sjdfaljfl
namespace 192.168.1.2 #eth0
namespace 192.168.1.3 #eth0
我们要通过字符串的处理,保证我们能够读到正确的DNS地址。
C++打开文件
打开文件肯定要调用打开文件的函数,这里我们采用C语言中的标准库stdio.h中的函数,stdio .h 头文件定义了三个变量类型、一些宏和各种函数来执行输入和输出。
本次用到的函数为fopen,参数为“文件名”,“打开模式”
模式如下表所示:
“r” | read: 为输入操作打开文件,文件必须存在。 |
---|---|
“w” | write: 为输出操作创建一个空文件,如果文件已存在,则将已有文件内容舍弃,按照空文件对待。 |
“a” | append: 为输出打开文件,输出操作总是再文件末尾追加数据,如果文件不存在,创建新文件。 |
“r+” | read/update: 为更新打开文件(输入和输出),文件必须存在 |
“w+” | write/update: 为输入和输出创建一个空文件,如果文件已存在,则将已有文件内容舍弃,按照空文件对待。 |
“a+” | append/update: 为输出打开文件,输出操作总是再文件末尾追加数据,如果文件不存在,创建新文件。 |
代码如下:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
if(fd!=NULL)
{
qDebug("open file success!!");
}
//ui->setupUi(this);
}
C++读取字符串
打开文件之后,要把字符串读到文件中,后续再对字符串进行解析,达到对文件进行处理的目的。
stdio.h中读取文件流的方法有两种。
1 | int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。 |
---|---|
2 | char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。 |
这里我们使用fgets函数获取数据。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
if(fd!=NULL)
{
qDebug("open file success!!");
}
char dns[255];
fgets(dns,255,fd);
qDebug("%s",dns);
//ui->setupUi(this);
}
至此,已经完成了第一行字符串的读取。
字符串处理
string .h 头文件定义了一个变量类型、一个宏和各种操作字符数组的函数。
8 | char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。 |
---|---|
9 | int strcmp(const char *str1, const char *str2) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较。 |
10 | int strncmp(const char *str1, const char *str2, size_t n) 把 str1 和 str2 进行比较,最多比较前 n 个字节。 |
11 | int strcoll(const char *str1, const char *str2) 把 str1 和 str2 进行比较,结果取决于 LC_COLLATE 的位置设置。 |
14 | size_t strcspn(const char *str1, const char *str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。 |
17 | char *strpbrk(const char *str1, const char *str2) 检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,则停止检验,并返回该字符位置。 |
18 | char *strrchr(const char *str, int c) 在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。 |
19 | size_t strspn(const char *str1, const char *str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。 |
20 | char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。 |
以上函数都可以进行字符串比较,以确定当前我们是否能够将该行字符串确定为是DNS地址的字符串。
我们选择strncmp函数进行处理,比较其前n个字节,看是否符合我们的要求。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
if(fd!=NULL)
qDebug("open file success!!");
char dns[255];
fgets(dns,255,fd);
qDebug("%s",dns);
if(strncmp(dns,"namespace",6)==0)
qDebug("this is dns");
else
qDebug("this is not dns");
//ui->setupUi(this);
}
通过比较可以确认出是否属于namespace,我们还要将整个文件读完,以获取到所有的dns数据。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
if(fd!=NULL)
qDebug("open file success!!");
char dns[255];
while(!feof(fd))//当未读到结束时
{
fgets(dns,255,fd);
qDebug("%s",dns);
if(strncmp(dns,"namespace",6)==0)
qDebug("this is dns");
else
qDebug("this is not dns");
}
//ui->setupUi(this);
}
至此,我们已经解析出了整个文件中的dns那一行数据,我们如何再准确的解析出dns地址呢?
我们使用C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。该函数的用法十分巧妙,第一次获取到的数据如果不符合需求,可以继续进行执行函数,注意传参,可继续获取剩余部分的字符串。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
char dns1[16];
bool dns1_flag;
//boot dns2_flag;
char dns2[16];
FILE *fd=fopen("C:\\Users\\NGG\\Desktop\\dns.txt","r");
if(fd!=NULL)
qDebug("open file success!!");
char dns[255];
while(!feof(fd))//当未读到结束时
{
fgets(dns,255,fd);
qDebug("%s",dns);
if(strncmp(dns,"namespace",6)==0){
strtok(dns," ");//第一次分割,获取第一部分字符串。
qDebug("%s",dns);
char *tmp=strtok(NULL," ");//获取第二部分字符串,第二部分字符串即我们需要的字符串。
if(dns1_flag==0)
{
dns1_flag=1;
strcpy(dns1,tmp);
}
else
{
strcpy(dns2,tmp);
}
qDebug("%s",dns1);
qDebug("this is dns");
}
else
qDebug("this is not dns");
}
qDebug("dns1=%sdns2=%s",dns1,dns2);
//ui->setupUi(this);
}
参考文章:C 标准库 - 参考手册 https://www.runoob.com/cprogramming/c-standard-library.html