Glib学习(23) IO通道 IO Channels
glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/
glib帮助文档:https://developer.gnome.org/glib/
IO通道 - 可移植的支持使用文件,管道和套接字
Includes
#include
描述
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
还没有评论,来说两句吧...