1、將最近用到的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;
//----------------------------------------------------------3、 ------------------------------------------------------------------------
//在下面的函數中,除了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;
}
2、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;
}
/*
該函數執行結果是大體上能夠看出來事件源是串行的即單線程
*/
3、glib的xml解析功能順便使用簡單的回調函數node
//程序功能:使用回調函數的方式調用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時,oop
over,glib待續。。。測試