glib简单记录包括字符串,主循环,回调函数和xml解析
一、将最近用到的glib字符串功能整理了下直接用程序记录比较好看懂
#define MAX_LEN 100
gchar * demo (char* msg, ...)
{
gchar * pcfgfile = NULL,* para = NULL;
va_list argp;
va_start(argp,msg);//msg其实指的是第一个参数,这个函数是让argp指向demo实参的栈底,参数是按从右往左的顺序压入栈的,argp不包含msg
pcfgfile = g_strdup_vprintf("%s %s %s %d",argp);
va_end(argp);
return pcfgfile;
}
int main(void){
gchar * pfilename = "houjiao";
gchar * strdouble = "11.11";
gchar * strint = "123456;8910";
gchar *test_str = NULL,* hj = NULL;
gint len = 0;
gchar buff_str[MAX_LEN+1];
guint64 imsi = 123456789;
gdouble test_duble = 0.0;
gchar **str_array = NULL;
//----------------------------------------------------------一 ------------------------------------------------------------------------
//下面的这些函数会返回一个新的字符串缓冲区的指针,所以你在使用完后必须要释放它们。
//--------------------------------------------------------------------------------------------------------------------------------------
/*
gchar *g_strdup(const gchar *str)
复制str并返回它的一个拷贝。并非返回原来字符串的指针而是重新申请一块内存将其指针返回。*/
hj = g_strdup(pfilename);
test_str = g_strdup(hj);
g_free(hj);
hj = NULL;
g_print("%s\n",test_str); //输出good
/*
gchar *strnfill(gsize length, gchar *fill_char)
创建一个长度为length并被fill_char填充的字符串。如果fill_char为0则创建一个空字符串 */
test_str = g_strnfill(10,0);
g_print("%s\n",test_str);
g_free(test_str);
test_str = NULL;
/*
gchar *g_strdup_printf(const gchar *format, ...)
像sprintf()一样格式化字符串和参数。但是,你没必要像sprintf()一样创建和指定一个缓冲区,GLib将这些自动做了。适合用于字符串拼 */
test_str = g_strdup_printf("%s_%u",pfilename,1);
g_print("%s\n",test_str);
/*测试g_strdup_vprintf的拼接功能 类似上面g_strdup_printf函数的功能*/
test_str = demo("","hj","is","number",1);//输出this is a demo!
g_print("%s\n",test_str);
g_free(test_str);
test_str = NULL;
/*
gchar *g_strconcat(const gchar *string1, ..., NULL)
它接受任意数量的string作为参数,并返回它们的连接后的字符串。必须将NULL作为这个函数的最后一个参数 */
hj = g_strdup(pfilename);
test_str = g_strconcat(" ",hj,":","good person",NULL);//输出 houjiao:good person
g_print("%s\n",test_str);
g_free(test_str);
test_str = NULL;
//----------------------------------------------------------二 ------------------------------------------------------------------------
//在下面的函数中,你应该为返回的结果申请空间。GLib并不会返回一个拷贝给你。它们与C相对应的函数非常像,参数要包含一个足够大的缓冲区来进行字符串处理。
//--------------------------------------------------------------------------------------------------------------------------------------
/*
gchar *g_stpcpy(gchar *dest, const gchar *src)
拷贝src到dest,包括最后的NULL字符。如果它执行成功,会返回dest中结束符拷贝的指针。*/
test_str = (gchar *)g_malloc0(strlen(hj));
g_stpcpy(test_str,hj);//函数返回的是结束符拷贝的指针这里即返回空字符串
g_print("%s\n",test_str);//输出,good
g_slice_free1(strlen(hj),test_str);
test_str = NULL;
/*
gint g_snprintf(gchar *string, gulong n, const gchar *format, ...)
你必须确保string有足够大的空间。而且你必须要用n来指定这个缓冲区的大小。返回值是输出字符串的长度,也有可能这个输出字符串为了适应缓冲区的大小而被截断 */
len += g_snprintf(buff_str+len,MAX_LEN-len,"%d,%d,%d,%"G_GINT64_FORMAT"",1,2,3,imsi);
g_print("%s\n",buff_str);//输出1,2,3,123456789
/*测试g_strchug删除字符串开始的空格*/
test_str = g_strconcat(" ",hj,":","good person ",NULL);
test_str = g_strchug(test_str);//输出houjiao:good person 光标在这
g_print("%s\n",test_str);
/*
gchar *g_strchomp(gchar *string)
将string结尾的空格都删掉,返回string */
test_str = g_strchomp(test_str);
g_print("%s\n",test_str);//houjiao:good person
g_free(test_str);
test_str = NULL;
/*
gchar *g_strstrip(gchar *string)
将string开头和结尾的空白字符都删掉,返回string。*/
test_str = g_strconcat(" ",hj,":","good person ",NULL);
test_str = g_strstrip(test_str);
g_print("%s\n",test_str);//输出houjiao:good person
/*
gchar *g_strdelimit(gchar *string, const gchar *delimiters, gchar *new_delimiter)
将string中的delimiters各个字符都替换为new_delimiter这一个字符 */
test_str = g_strdelimit(test_str,"good",'a');
g_print("%s\n",test_str);//haujiaa:aaaa persan
g_free(test_str);
test_str = NULL;
//----------------------------------------------------------三、 ------------------------------------------------------------------------
//在下面的函数中,除了g_ascii_dtostr()之外,都不改变它们的参数。
//--------------------------------------------------------------------------------------------------------------------------------------
/*
gchar *g_strstr_len(const gchar *haystack, gssize haystack_len, const gchar *needle)
在haystack中遍历haystack_len长度,如果找到了needle字串,则返回这个位置的指针,如果没有找到则返回NULL。*/
test_str = g_strstr_len(pfilename,strlen(pfilename),"jia");
g_print("%s\n",test_str);//输出jiao
test_str = NULL;
/*
gchar *g_strrstr(const gchar *haystack, const gchar *needle)
类似于g_strstr_len,这个函数将会从后面开始查找,但是它并没有haystack_len参数。 */
test_str = g_strrstr(pfilename,"jia");
g_print("%s\n",test_str);//输出jiao
test_str = NULL;
/*
gchar *g_strrstr_len(gchar *haystack, gssize haystack_len, gchar *needle)
与g_strrstr()相同,但是它只在前haystack_len个字符中查找,第二个参数是-1表示在整个字符串中找*/
test_str = g_strrstr_len(pfilename,-1,"a");
g_print("%s\n",test_str);
test_str = g_strrstr_len(pfilename,5,"a");
g_print("%s\n",test_str);//输出(null)
/*
gdouble g_ascii_strtod(const gchar *nptr, gchar **endptr)
将string转为双字长度的浮点数。如果你提供了一个有效的endptr指针地址,这个函数会将指针设置到string中被转换的最后一个字符的位置*/
test_duble = g_ascii_strtod(strdouble,NULL);
g_print("%.2f\n",test_duble);//输出11.11
/*
gchar **g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens)
使用delimiter来将string切割成至多max_tokens个部分。返回值是新申请的一个字符串数组,用来保存被切割的这些部分。
这个字符串数组必须由你自己释放。 如果输入字符串是空的,这个返回值也是一个空的数组。 该法不改变原string */
str_array = g_strsplit(strint,";",3);
g_print("%s,%s\n",str_array[0],str_array[1]);//123456,8910
/*
gchar *g_str_joinv(const gchar *separator, gchar **str_array)
将字符串数组组合成单个字符串,并将这个新申请的字符串返回。如果separator不空,g_str_joinv()会在每个字符串之间添加上一个separator分隔符。*/
test_str = g_strjoinv(",",str_array);
g_print("%s\n",test_str);//123456,8910
g_strfreev(str_array);
str_array = NULL;
g_free(test_str);
test_str = NULL;
/*测试g_ascii_strtoll将字符串转成对应整形的功能第三个参数是指的几进制*/
test_str =strchr(strint,';');
len = (gint)g_ascii_strtoll(strint,NULL,10);
g_print("%d\n",len);//输出123456
strint = test_str +1;
len = (gint)g_ascii_strtoll(strint,NULL,10);
g_print("%d\n",len);//输出8910
g_free(test_str);
test_str = NULL;
return TRUE;
}
二、glib的主循环功能主要是为了看看主循环的串行
/*
自定义的事件源是一个继承 GSource 的结构体,即自定义事件源的结构体 的第一个成员是 GSource 结构体, 其后便可放置程序所需数据, 例如:*/
typedef struct _MySource MySource;
struct _MySource
{
GSource source;
gchar text[256];
};
/*
实现了事件源数据结构的定义之后,还需要实现事件源所规定的接口,主要为 prepare, check, dispatch, finalize 等事件处理函数(回调函数),它们包含于 GSourceFuncs 结构体中。
将 GSourceFuncs 结构以及事件源结构的存储空间宽度作为参数传给 g_source_new 便可构造一个新的事件源,继而可使用 g_source_attach 函数将新的事件源添加到主循环上下文中
*/
static gboolean prepare(GSource *source, gint *timeout)
{
*timeout = 0;
return TRUE;
}
static gboolean check(GSource *source)
{
return TRUE;
}
static gboolean dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
int i = 0;
MySource *mysource = (MySource *)source;
for (;i<6;i++)
{
g_print("%s%d\n", mysource->text,i);
}
return TRUE;
}
/*
g_main_loop_run 函数运行时,会迭代访问 GMainContext 的事件源列表,步骤大致如下:
a. g_main_loop_run 通过调用事件源的 prepare 接口并判断其返回值以确定各事件源是否作好准备。如果各事件源的 prepare 接口的返回值为 TRUE,即表示该事件源已经作好准备,否则表示尚未做好准备。显然,上述程序所定义的事件源是已经作好了准备。
b. 若某事件源尚未作好准备 ,那么 g_main_loop 会在处理完那些已经准备好的事件后再次询问该事件源是否作好准备 ,这一过程是通过调用事件源的 check 接口而实现的,如果事件源依然未作好准备,即 check 接口的返回 FALSE,那么 g_main_loop_run 会让主事件循环进入睡眠状态。
主事件循环的睡眠时间是步骤 a 中遍历时间源时所统计的最小时间间隔 ,例如在 prepare 接口中可以像下面这样设置时间间隔。到达一定时间后, g_main_loop_run 会唤醒主事件循环,再次询问。如此周而复始,直至事件源的 prepare 接口返回值为 TRUE。*/
int main1(void)
{
GMainLoop *loop = g_main_loop_new(NULL, TRUE);
GMainContext *context = g_main_loop_get_context(loop);
GSourceFuncs source_funcs = {prepare, check, dispatch, NULL};
GSource *source = g_source_new(&source_funcs, sizeof(MySource));
g_sprintf(((MySource *)source)->text, "Hello world");
g_timeout_add(100, timeout_func, loop);
g_source_attach(source, context);
g_source_unref(source);
g_main_loop_run(loop);
g_main_context_unref(context);
g_main_loop_unref(loop);
return 0;
}
/*
该函数执行结果是大致上可以看出来事件源是串行的即单线程
*/
三、glib的xml解析功能顺便使用简单的回调函数
//程序功能:使用回调函数的方式调用xml和txt两种文件的读取函数。
xml文件里面的内容如下
<?xml version="1.0" encoding="UTF-8"?>
<NM id="15009244480" name="houjiao">
<title>name ege sex what emotion</title>
<v>hq 24 female friend love</v>
<v>ld 24 female friend love</v>
<v>wj 25 female friend love</v>
<v>wff 25 female friend love</v>
</NM>
txt文件里面内容如下
hq is 24 years older,and she is my friend.
ld is 24 years older,and she is my friend.
wj is 25 years older,and she is my friend.
wff is 25 years older,and she is my friend.
然后程序如下,注释已经很清晰了
#include "glib.h"
#include "string.h"
#include "stdio.h"
//定义函数指针即回调函数的类型
typedef gboolean (*CallBackFileRead)(gchar *);
typedef struct _FriendNode
{
gchar * myname;
gchar * hername;
gchar * what;
gchar * emotion;
guint8 ege;
guint64 tel_id;
gboolean txt_pasre_flag;
}FriendNode;
/*当遇到元素开始时,将其属性名全存到attribute_name数组中,对应的属性值存入value_cursor数组中,所以属性名和属性值是同时++然后就会取到下一个属性直到取完*/
static void start( GMarkupParseContext * context,
const gchar * element_name,
const gchar * * attribute_names,
const gchar * * attribute_values,
gpointer user_data,
GError * * error )
{
const gchar * * name_cursor = attribute_names;
const gchar * * value_cursor = attribute_values;
FriendNode * friend_node =(FriendNode *)user_data ;
if (g_strcmp0(element_name,"v") == 0)
{
friend_node->txt_pasre_flag = TRUE;
}
else if (g_strcmp0(element_name,"NM") == 0)
{
while (*name_cursor)
{
if (g_strcmp0(*name_cursor, "id") == 0)
{
friend_node->tel_id = (guint64)g_ascii_strtoull(*value_cursor,NULL,10);
}
else if (g_strcmp0(*name_cursor, "name") == 0)
{
friend_node->myname = g_strdup (*value_cursor);
}
name_cursor++;
value_cursor++;
}
g_print("My name is %s,my telphone num is %"G_GUINT64_FORMAT" \n",friend_node->myname,friend_node->tel_id);
}
}
//一个元素结束时调用,一般可以在你想要取值的元素设置标记。
static void end( GMarkupParseContext * context,
const gchar * element_name,
gpointer user_data,
GError * * error )
{
FriendNode * friendnode = (FriendNode*)user_data;
if (g_strcmp0(element_name,"v") == 0)
{
friendnode->txt_pasre_flag = FALSE;
}
}
//一般xml里面要取得最重要的是内容,因此按照内容格式不同,拆分字符串的方式不同。
static void text( GMarkupParseContext * context,
const gchar * text,
gsize text_len,
gpointer user_data,
GError * * error )
{
const gchar * s = text;
gchar * ss = NULL;
int i=0; //列索引
FriendNode * friendnode = (FriendNode *)user_data;
if (friendnode->txt_pasre_flag)
{
while ((ss = strchr((gchar *)s,' ')) && i<=3)
{
switch (i)
{
case 0:
friendnode->hername = g_strndup(s,ss-s);
break;
case 1:
friendnode->ege =(gint8)g_ascii_strtoull(s,NULL,10);
break;
case 3:
friendnode->what = g_strndup(s,ss-s);
break;
default:
break;
}
s = ss + 1;
i++;
}
if (i == 4)
{
friendnode->emotion =g_strdup(s);
}
g_print("%s is %d years older,and she is my %s who I %s\n",friendnode->hername,friendnode->ege,friendnode->what,friendnode->emotion);
g_free(friendnode->hername);
g_free(friendnode->what);
g_free(friendnode->emotion);
}
}
//xml解析类回调函数的实现
gboolean ReadXmlFile(gchar * filename){
GMarkupParser gparser = {0}; //GMarkup解析器
GMarkupParseContext *gparsecontext = NULL; //GMarkup解析上下文
FriendNode friend_node = {0};
char * buf;
gsize length;
/*创建解析器上下文第三个参数是用来传给 GMarkupParser解析器函数即start,text和end里面用的 */
gparsecontext = g_markup_parse_context_new(&gparser,(GMarkupParseFlags)0, &friend_node, NULL);
if (gparsecontext == NULL)
{
return FALSE;
}
/*给gparser的函数指针赋值*/
gparser.start_element = start;
gparser.text = text;
gparser.end_element =end;
/* g_file_get_contents(const gchar *filename,gchar **contents,gsize *length,GError **error);
是用于将文件的内容读入到一个buf中,length是用来存储字符串长度的变量可设为null,读取成功返回ture读取失败返回false和最后一个参数 */
if ((FALSE == g_file_get_contents(filename, &buf, &length,NULL)))
{
return FALSE;
}
/*开始解析buf里面的字符串,调用gparser的三个函数,xml文件里面一个元素包括,元素名,属性值和元素内容,一个元素的start标志为:<元素名[属性]>,元素的end标志为:</元素名> 包含在元素开始和元素结束之间的变是该元素的text*/
if (g_markup_parse_context_parse(gparsecontext, buf, length, NULL) == FALSE)
{
g_message("load xml file failed!");
g_free(buf);
g_markup_parse_context_free(gparsecontext);
gparsecontext = NULL;
return FALSE;
}
}
//csv解析类回调函数实现
gboolean ReadTxtFile(gchar * filename){
FILE * ftxt_file = NULL;
gchar buf[100] = {'\0'};
if (fopen_s(&ftxt_file,filename,"rb") != 0)
{
g_print("open file error");
return FALSE;
}
//fgets遇到文件结束或读取错误时返回null
while(fgets(buf, 100, ftxt_file))
{
g_print("%s",buf);
}
fclose(ftxt_file);
return TRUE;
}
void XmlTxtParseCallBack(gchar* filename, CallBackFileRead pFun) //模拟API函数
{
//回调解析文件类函数
if (!pFun(filename))
{
g_print("parse error");
}
}
//1.在main中的XmlTxtParseCallBack接口函数调用了回调函数,当然xml解析和txt解析的两个函数可以像普通函数一样被调用,但是当它作为参赛传递给被调函数时就称为回调函数了。
//2.回调函数实际上就是在调用某个函数(通常是API函数时),将自己的一个函数(这个函数叫回调函数)的地址作为参数传递给那个函数,那个函数在需要的时候利用传递的地址调用回调函数,这种模式很适合异步模块之间的调用。
//3.用计算机原理来说,回调函数就是一个中断处理函数,由系统在符合你设定条件时自动调用,你要做的只有三步,一声明回调函数类型,二实现回调函数,三,设置触发条件(即把你的回调函数名转化为函数指针作为参数用于调用)。
int main()
{
gchar * filename = "F:\\test\\input\\hj.txt";
if (g_str_has_suffix(filename,".xml"))
{
XmlTxtParseCallBack(filename,ReadXmlFile);
}
else if (g_str_has_suffix(filename,".txt"))
{
XmlTxtParseCallBack(filename,ReadTxtFile);
}
else
{
g_print("can't parse this file type");
}
return 0;
}
执行结果是:
当filename是**hj.txt时,
当file那么是**hj.xml时,
over,glib待续。。。
glib简单记录包括字符串,主循环,回调函数和xml解析的更多相关文章
- RCF的简单使用教程以及什么是回调函数
RCF的使用教程 RCF(Remote Call Framework)是一个使用C++编写的RPC框架,在底层RCF支持多种传输实现方式(transport implementations). 包括T ...
- android中回调函数机制完全解析
1.在要调用的业务操作中,创建一个接口,在接口中创建方法,这个方法表示的是我们原先要在业务类中执行的操作 public interface BackUpSmsListener { /** * 设置总进 ...
- Cocos2d-x 3.2 学习笔记(十六)保卫萝卜 游戏主循环与定时器
保卫萝卜~想法一直存在于想法,实战才是硬道理!有想法就去实现,眼高手低都是空谈. 一.游戏主循环GameSchedule 主循环是游戏处理逻辑,控制游戏进度的地方,处理好主循环是很重要的 ...
- libevent源码学习(13):事件主循环event_base_loop
目录开启事件主循环执行事件主循环校对时间 阻塞/非阻塞处理激活队列中的event事件主循环的退出event_base_loopexitevent_base_loopbreak开启事件主循环 ...
- wxWidgets源码分析(2) - App主循环
目录 APP主循环 MainLoop 消息循环对象的创建 消息循环 消息派发 总结 APP主循环 MainLoop 前面的wxApp的启动代码可以看到,执行完成wxApp::OnInit()函数后,接 ...
- jQuery 源码解析(八) 异步队列模块 Callbacks 回调函数详解
异步队列用于实现异步任务和回调函数的解耦,为ajax模块.队列模块.ready事件提供基础功能,包含三个部分:Query.Callbacks(flags).jQuery.Deferred(funct) ...
- 理解和使用 JavaScript 中的回调函数
理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报 分类: JavaScript(4) 目录( ...
- 关于js的callback回调函数的理解
回调函数的处理逻辑理解:所谓的回调函数处理逻辑,其实就是先将回调函数的代码 冻结(或者理解为闲置),接着将这个回调函数的代码放到回调函数管理器的队列里面. 待回调函数被触发调用的时候,对应的回调函数的 ...
- 理解javascript中的回调函数(callback)【转】
在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...
随机推荐
- jq 按回车键 登陆
$("body").keydown(function(e) { if (event.which == "13") {//keyCode= ...
- Linux系统下如何查看物理内存占用率
Linux系统下如何查看物理内存占用率 Linux下看内存和CPU使用率一般都用top命令,但是实际在用的时候,用top查看出来的内存占用率都非常高,如:Mem: 4086496k total, ...
- HTML的footer置于页面最底部的方法
方法一:footer高度固定+绝对定位 <html> <head> <style type="text/css"> html{height:%; ...
- MathType中输入不了汉字如何处理
MathType作为一款常见的数学公式编辑器在编辑数学公式时,不仅可以输入英文字符,对中文也有很好的兼容性.但是有些用户在使用MathType编辑公式时,发现一些汉字是输入不进去的,这个时候我们就需要 ...
- Hive将txt、csv等文本文件导入hive表
1.将txt文本文件放置hdfs目录下 2.登录hive并进入到指定数据库 3.创建表 create external table if not exists fun_user_external ( ...
- Spring_day02--log4j介绍_Spring整合web项目演示
log4j介绍 1 通过log4j可以看到程序运行过程中更详细的信息 (1)经常使用log4j查看日志 2 使用 (1)导入log4j的jar包 (2)复制log4j的配置文件,复制到src下面 3 ...
- SqlSession接口和Executor
mybatis框架在操作数据的时候,离不开SqlSession接口实例类的作用.可以说SqlSession接口实例是开发过程中打交道最多的一个类.即是DefaultSqlSession类.如果笔者记得 ...
- cocos2dx热更新tmx的一个坑
游戏项目中使用了tmx地图,当对tmx文件进行热更新时,进入该地图总是宕机,纠结了几小时终于发现,cocos读取tmx文件时,会默认tmx关联的图集文件和tmx在同一目录,然而那个图集文件并没有在热更 ...
- 用VS不同版本打开项目,报错:MS Build Error MSB4019: Microsoft.WebApplication.targets was not found
本例是在用VS2008打开项目是报错 未找到C:\Program Files\MSBuild\Microsoft\VisualStudio\V10.0 In the last article Buil ...
- Struts2中的类型转换失败
类型转换失败: 若 Action 类没有实现 ValidationAware 接口: Struts 在遇到类型转换错误时仍会继续调用其 Action 方法, 就好像什么都没发生一样. 若 Action ...