glib源碼下載:http://ftp.gnome.org/pub/gnome/sources/glib/
glib幫助文檔:https://developer.gnome.org/glib/
IO通道 - 可移植的支持使用文件,管道和套接字
Includes
#include <glib.h>
描述
GIOChannel數據類型旨在提供一種可移植的方法,用於使用文件描述符,管道和套接字,並將它們集成到main event loop。 目前,在UNIX平臺上提供完全支持,對Windows的支持僅部分完成。
要在UNIX系統上創建新的GIOChannel,請使用g_io_channel_unix_new()。 這適用於普通文件描述符,管道和套接字。 或者,可以使用g_io_channel_new_file()以與系統無關的方式爲文件創建通道。
創建GIOChannel後,可以使用函數g_io_channel_read_chars(),g_io_channel_write_chars(),g_io_channel_seek_position()和g_io_channel_shutdown()以通用方式使用它。
要將GIOChannel添加到main event loop,請使用g_io_add_watch()或g_io_add_watch_full()。 在這裏,您可以在GIOChannel上指定您感興趣的事件,並提供在發生這些事件時要調用的函數。
創建GIOChannel實例,初始引用計數爲1. g_io_channel_ref()和g_io_channel_unref()可分別用於遞增或遞減引用計數。 當引用計數降至0時,釋放GIOChannel。 (雖然它不會自動關閉,除非它是使用g_io_channel_new_file()創建的。)使用g_io_add_watch()或g_io_add_watch_full()增加通道的引用計數。
新函數g_io_channel_read_chars(),g_io_channel_read_line(),g_io_channel_read_line_tring(),g_io_channel_read_to_end(),g_io_channel_write_chars(),g_io_channel_seek_position()和g_io_channel_flush()不應與不推薦使用的函數g_io_channel_read(),g_io_channel_write()和g_io_channel_seek混合使用( )在同一channel上。
函數
g_io_channel_unix_new ()
給定文件描述符創建新的GIOChannel。 在UNIX系統上,這適用於普通文件,管道和套接字。
返回的GIOChannel的引用計數爲1。
GIOChannel的默認編碼是UTF-8。 如果您的應用程序正在使用via管道從命令讀取輸出,則可能需要使用g_io_channel_set_encoding()函數將編碼設置爲當前語言環境的編碼(請參閱g_get_charset())。 默認情況下,當刪除對GIOChannel數據結構的最終引用時,將不會關閉傳遞的fd。
如果要在沒有解釋的情況下讀取原始二進制數據,則使用NULL爲編碼參數調用g_io_channel_set_encoding()函數。
此功能在Windows上的GLib中也可用,但您應該避免在Windows上使用它。 文件描述符和套接字的域重疊。 如果傳遞給此函數的參數恰好是有效的文件描述符和套接字,則GLib無法知道您的意思。 如果發生這種情況,則會發出警告,並且GLib假定它是您所指的文件描述符。
返回值
一個新的GIOChannel。
g_io_channel_unix_get_fd ()
返回GIOChannel的文件描述符。
在Windows上,此函數返回GIOChannel的文件描述符或套接字。
g_io_channel_init ()
初始化GIOChannel結構。
在創建GIOChannel時,上述每個函數都會調用它,因此應用程序員通常不需要這樣做(除非您要創建新類型的GIOChannel)。
g_io_channel_new_file ()
使用mode模式將文件文件名作爲GIOChannel打開。 當刪除對它的最後一個引用時,該channel將被關閉,因此不需要調用g_io_channel_close()(儘管這樣做不會導致問題,只要在關閉後沒有嘗試訪問該通道)。
參數
mode
“r”,“w”,“a”,“r +”,“w +”,“a +”之一。 這些與fopen()中的含義相同
返回值
成功時的GIOChannel,失敗時爲NULL。
g_io_channel_read_chars ()
使用新API替換g_io_channel_read()。
參數
count
緩衝區的大小。 請注意,如果剩餘數據不是完整字符,即使緩衝區中有數據,緩衝區也可能無法完全填充。
[in]
bytes_read
讀取的字節數。 如果count <6並且channel的編碼爲非NULL,則即使成功也可能爲零。 這表示下一個UTF-8字符對於緩衝區來說太寬。
[out][optional]
返回值
操作的狀態。
g_io_channel_read_unichar ()
從通道讀取Unicode字符。 無法在具有NULL編碼的通道上調用此函數。
g_io_channel_read_line ()
從GIOChannel讀取一行(包括終止字符)到新分配的字符串。 如果返回值爲G_IO_STATUS_NORMAL,則str_return將包含已分配的內存。
參數
str_return
從GIOChannel讀取的行,包括行終止符。 不再需要時,應使用g_free()釋放此數據。 這是一個以空字符結尾的字符串。 如果返回零長度,則將爲NULL。
[out]
length
存儲讀取數據長度的位置,或NULL。
[out][optional]
terminator_pos
存儲行終止符位置的位置,或NULL。
[out][optional]
error
返回GConvertError或GIOChannelError類型錯誤的位置
返回值
操作的狀態。
g_io_channel_read_line_string ()
使用GString作爲緩衝區從GIOChannel讀取一行。
參數
g_io_channel_read_to_end ()
從文件中讀取所有剩餘數據。
返回值
G_IO_STATUS_NORMAL成功。 此函數永遠不會返回G_IO_STATUS_EOF。
g_io_channel_write_unichar ()
將Unicode字符寫入通道。 無法在具有NULL編碼的通道上調用此函數。
g_io_channel_flush ()
刷新GIOChannel的寫緩衝區。
返回值
操作的狀態:G_IO_STATUS_NORMAL,G_IO_STATUS_AGAIN或G_IO_STATUS_ERROR之一。
g_io_channel_shutdown ()
關閉IO通道。 如果flush爲TRUE,則將刷新任何要寫入的待處理數據。 在使用g_io_channel_unref()刪除最後一個引用之前,不會釋放該通道。
g_io_create_watch ()
創建在滿足給定通道條件時調度的GSource。 例如,如果condition是G_IO_IN,則當有可用於讀取的數據時,將調度source。
對於您希望以默認優先級將source添加到默認主循環上下文的情況,g_io_add_watch()是同一功能的簡單接口。
g_io_add_watch ()
使用默認優先級將GIOChannel添加到默認主循環上下文中。
g_io_add_watch_full ()
將GIOChannel添加到具有給定優先級的默認主循環上下文中。
這在內部使用g_io_create_watch()創建一個主循環source,並使用g_source_attach()將其附加到主循環上下文。 如果需要更好的控制,可以手動執行這些步驟。
[rename-to g_io_add_watch]
gboolean
(*GIOFunc) (GIOChannel *source,
GIOCondition condition,
gpointer data);
指定傳遞給g_io_add_watch()或g_io_add_watch_full()的函數類型,該函數在滿足GIOChannel上的請求條件時調用。
g_io_channel_get_line_term ()
這將返回GIOChannel用於確定文件在哪裏發生換行的字符串。 值NULL表示自動檢測。
g_io_channel_set_line_term ()
這將設置GIOChannel用於確定文件中斷行發生位置的字符串。
g_io_channel_get_buffered ()
返回緩衝通道。
g_io_channel_set_buffered ()
只有在通道編碼爲NULL時才能設置緩衝狀態。 對於任何其他編碼,必須緩衝通道。
如果刷新了通道的內部緩衝區,則只能將緩衝通道設置爲無緩衝。 返回G_IO_STATUS_EOF的新創建的頻道或頻道不需要這樣的flush。 對於只寫通道,調用g_io_channel_flush()就足夠了。 對於所有其他通道,可以通過調用g_io_channel_seek_position()來刷新緩衝區。 這包括尋找類型G_SEEK_CUR和零偏移的可能性。 請注意,這意味着一旦從其中讀取數據,就無法將基於套接字的通道設置爲無緩衝。
在無緩衝通道上,如果維護舊代碼是必要的,則可以安全地混合來自新舊API的讀寫調用。
緩衝通道的默認狀態。
示例代碼:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <glib.h>
#include <glib/gprintf.h>
void channel_unix_new_test(void)
{
g_printf ("%s() in\n", __func__);
int fd = open("test.txt", O_RDONLY);
GIOChannel *giofile = g_io_channel_unix_new (fd);
gchar *str_return;
gsize length, terminator_pos;
GError *error = NULL;
GIOStatus giostatus = g_io_channel_read_line (giofile,
&str_return,
&length,
&terminator_pos,
&error);
if (giostatus == G_IO_STATUS_NORMAL)
g_printf ("read_line:%s, length:%ld, terminator_pos:%ld\n", str_return, length, terminator_pos);
else if (giostatus == G_IO_STATUS_ERROR)
g_printf ("read_line error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("read_line error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("read_line error G_IO_STATUS_AGAIN:%s\n", error->message);
GString *buffer = g_string_new (NULL);
giostatus = g_io_channel_read_line_string (giofile,
buffer,
&terminator_pos,
&error);
if (giostatus == G_IO_STATUS_NORMAL)
g_printf ("read_line_string:%s\n", buffer->str);
else if (giostatus == G_IO_STATUS_ERROR)
g_printf ("read_line_string error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("read_line_string error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("read_line_string error G_IO_STATUS_AGAIN:%s\n", error->message);
g_string_free (buffer, TRUE);
giostatus = g_io_channel_read_to_end (giofile,
&str_return,
&length,
&error);
if (giostatus == G_IO_STATUS_NORMAL)
g_printf ("read_to_end:%s, length:%ld\n", str_return, length);
else if (giostatus == G_IO_STATUS_ERROR)
g_printf ("read_to_end error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("read_to_end error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("read_to_end error G_IO_STATUS_AGAIN:%s\n", error->message);
gint gfd = g_io_channel_unix_get_fd (giofile);
g_io_channel_shutdown (giofile, TRUE, &error);
close(gfd);
g_printf ("%s() out\n", __func__);
}
void channel_read_chars_test(void)
{
g_printf ("%s() in\n", __func__);
GError *error = NULL;
GIOChannel *giofile = g_io_channel_new_file ("test.txt",
"r",
&error);
gchar *buf = g_new0(gchar, 1024);
gsize bytes_read;
GIOStatus giostatus = g_io_channel_read_chars (giofile,
buf,
1024,
&bytes_read,
&error);
if (giostatus == G_IO_STATUS_NORMAL)
g_printf ("read_chars:%s, length:%ld\n", buf, bytes_read);
else if (giostatus == G_IO_STATUS_ERROR)
g_printf ("read_chars error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("read_chars error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("read_chars error G_IO_STATUS_AGAIN:%s\n", error->message);
g_io_channel_shutdown (giofile, TRUE, &error);
g_free (buf);
g_printf ("%s() out\n", __func__);
}
void channel_read_unichar_test(void)
{
g_printf ("%s() in\n", __func__);
GError *error = NULL;
GIOChannel *giofile = g_io_channel_new_file ("ansi.txt",
"r",
&error);
GError *err = NULL;
GIOStatus giostatus = g_io_channel_set_encoding (giofile,
"ANSI",
&err);
gunichar thechar;
giostatus = g_io_channel_read_unichar (giofile,
&thechar,
&error);
if (giostatus == G_IO_STATUS_NORMAL)
g_printf ("read_unichar:%d\n", thechar);
else if (giostatus == G_IO_STATUS_ERROR)
g_printf ("read_unichar error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("read_unichar error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("read_unichar error G_IO_STATUS_AGAIN:%s\n", error->message);
g_io_channel_shutdown (giofile, TRUE, &error);
g_printf ("%s() out\n", __func__);
}
void channel_write_chars_test(void)
{
g_printf ("%s() in\n", __func__);
GError *error = NULL;
GIOChannel *giofile = g_io_channel_new_file ("write.txt",
"a+",
&error);
gsize bytes_written;
GIOStatus giostatus = g_io_channel_write_chars (giofile,
"g_io_channel_write_chars",
-1,
&bytes_written,
&error);
if (giostatus == G_IO_STATUS_ERROR)
g_printf ("write_chars error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("write_chars error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("write_chars error G_IO_STATUS_AGAIN:%s\n", error->message);
giostatus = g_io_channel_flush (giofile,
&error);
if (giostatus == G_IO_STATUS_ERROR)
g_printf ("flush error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("flush error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("flush error G_IO_STATUS_AGAIN:%s\n", error->message);
g_io_channel_shutdown (giofile, TRUE, &error);
g_printf ("%s() out\n", __func__);
}
gboolean GIOFifoFunc (GIOChannel *source, GIOCondition condition, gpointer data)
{
g_printf ("GIOFifoFunc data:%s\n", (char *)data);
g_printf ("condition:%d\n", condition);
if(condition & G_IO_HUP) {
g_error("error:Pipe Disconnected!\n");
}
GError *error = NULL;
gsize bytes_read;
gsize length, terminator_pos;
gchar *str_return;
GIOStatus giostatus = g_io_channel_read_line (source,
&str_return,
&length,
&terminator_pos,
&error);
if (giostatus == G_IO_STATUS_NORMAL)
g_printf ("read_line:%s, length:%ld, terminator_pos:%ld\n", str_return, length, terminator_pos);
else if (giostatus == G_IO_STATUS_ERROR)
g_printf ("read_chars error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("read_chars error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("read_chars error G_IO_STATUS_AGAIN:%s\n", error->message);
g_free (str_return);
return TRUE;
}
void FifoDestroyNotify (gpointer data)
{
g_printf ("FifoDestroyNotify data:%s\n", (char *)data);
}
gboolean TimeoutSourceFunc (gpointer user_data)
{
g_printf ("%s() in\n", __func__);
GMainLoop *loop = (GMainLoop *)user_data;
g_main_loop_quit (loop);
return FALSE;
}
void setup_child(gint input[]) {
g_printf ("%s() in\n", __func__);
GIOChannel *channel_read;
char *user_data = "test user data!";
// 關閉不必要的 Pipe 輸入
close(input[1]);
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
channel_read = g_io_channel_unix_new(input[0]);
if(channel_read == NULL) {
g_error("error:Unable to establish GIOChannels!\n");
}
guint source_id = g_io_add_watch_full(channel_read, G_PRIORITY_DEFAULT, G_IO_IN|G_IO_HUP, GIOFifoFunc, (gpointer) user_data, FifoDestroyNotify);
if(source_id == 0) {
g_error("error:Unable to add watch!\n");
}
g_timeout_add (1000, TimeoutSourceFunc, (gpointer)loop);
g_main_loop_run (loop);
g_source_remove (source_id);
g_printf ("g_source_remove\n");
sleep(1);
}
void setup_parent(gint output[]) {
g_printf ("%s() in\n", __func__);
sleep(1);
GIOChannel *channel_write;
GError *error = NULL;
gsize bytes_written;
// 關閉不用的 Pipe 輸出
close(output[0]);
// 建立 GIOChannel
channel_write = g_io_channel_unix_new(output[1]);
if(channel_write == NULL) {
g_error("錯誤:無法建立 GIOChannels!\n");
}
GIOStatus giostatus = g_io_channel_write_chars (channel_write,
"setup parent\n",
-1,
&bytes_written,
&error);
giostatus = g_io_channel_flush (channel_write, &error);
if (giostatus == G_IO_STATUS_ERROR)
g_printf ("flush error G_IO_STATUS_ERROR:%s\n", error->message);
else if (giostatus == G_IO_STATUS_EOF)
g_printf ("flush error G_IO_STATUS_EOF:%s\n", error->message);
else if (giostatus == G_IO_STATUS_AGAIN)
g_printf ("flush error G_IO_STATUS_AGAIN:%s\n", error->message);
sleep(5);
}
void io_add_watch(void)
{
g_printf ("%s() in\n", __func__);
gint parent_to_child[2];
if(pipe(parent_to_child) == -1) { // 開啓Pipe
g_error("Error:%s\n", g_strerror(errno));
return;
}
// fork 子程序
switch(fork()) {
case -1:
g_error("error:%s\n", g_strerror(errno));
break;
case 0: // 這是子程序
setup_child(parent_to_child);
break;
default: // 這是父程序
setup_parent(parent_to_child);
}
g_printf ("%s() out\n", __func__);
}
int main(int argc, char **argv)
{
g_printf ("main() in\n");
channel_unix_new_test();
channel_read_chars_test();
channel_read_unichar_test();
channel_write_chars_test();
io_add_watch();
g_printf ("main() out\n");
return 0;
}
輸出結果:
~/glibtest$ ./gio
main() in
io_add_watch() in
setup_parent() in
setup_child() in
GIOFifoFunc data:test user data!
condition:1
read_line:setup parent
, length:13, terminator_pos:12
TimeoutSourceFunc() in
FifoDestroyNotify data:test user data!
g_source_remove
io_add_watch() out
main() out
io_add_watch() out
main() out
文本文件:
ansi.txt
test.txt
write.txt