C Glib GIO - 如何异步列出文件
C Glib GIO - How to list files asynchronously
我正在使用 GTK 创建一个简单的文件查看器,我想异步加载新目录,以防止在加载时挂起整个程序。
在 GIO API 中有 g_file_enumerator_next_files_async
函数,允许以块的形式异步加载文件。但是我怎么知道目录列表何时完成?这是我想出的代码示例:
static void add_file_callback(GObject *direnum,
GAsyncResult *result,
gpointer user_data){
GError *error = NULL;
GList *file_list = g_file_enumerator_next_files_finish(
G_FILE_ENUMERATOR(direnum),
result, &error);
if( file_list == NULL ){
g_critical("Unable to add files to list, error: %s", error->message);
}
GList *next;
GFileInfo *info;
GtkTreeIter iter;
DirList *list = (DirList*)user_data;
while(file_list){
...add file to list
}
}
int read_dir(const gchar *path, DirList *list){
g_assert(list != NULL && list->store != NULL);
GtkTreeIter iter;
gtk_list_store_clear(list->store);
list->path = path;
GFile *dir = g_file_new_for_path(path);
GFileEnumerator *dirent = g_file_enumerate_children(dir,
"*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
NULL);
while( TRUE ){ /* <============================== When to end? */
g_file_enumerator_next_files_async(dirent,
BLOCK_SIZE,
G_PRIORITY_DEFAULT,
NULL,
add_file_callback,
list);
}
g_file_enumerator_close(dirent, NULL, NULL);
g_object_unref(dirent);
g_object_unref(dir);
return 0;
}
来自this g_file_enumerator_next_files_async
reference:
The callback can be called with less than num_files
files in case of error or at the end of the enumerator.
因此,如果回调接收的文件数少于 BLOCK_SIZE
,那么您就知道出现错误或没有更多文件可用。
如果发生这种情况,请设置一个标志,供 read_dir
中的循环检查。
要执行列表,您应该递归调用 g_file_enumerator_next_files_async
,而不是循环调用它们,示例如下:
static void add_file_callback(GObject *direnum,
GAsyncResult *result,
gpointer user_data){
GError *error = NULL;
GList *file_list = g_file_enumerator_next_files_finish(
G_FILE_ENUMERATOR(direnum),
result, &error);
if( error ){
g_critical("Unable to add files to list, error: %s", error->message);
g_object_unref(direnum);
g_error_free(error);
return;
}else if( file_list == NULL ){
/* Done listing */
g_object_unref(direnum);
return;
}else{
GList *node = file_list;
GFileInfo *info;
GtkTreeIter iter;
while(node){
info = node->data;
node = node->next;
...add to store
g_object_unref(info);
}
g_file_enumerator_next_files_async(G_FILE_ENUMERATOR(direnum),
BLOCK_SIZE,
G_PRIORITY_LOW,
NULL,
add_file_callback,
list);
}
g_list_free(file_list);
}
我正在使用 GTK 创建一个简单的文件查看器,我想异步加载新目录,以防止在加载时挂起整个程序。
在 GIO API 中有 g_file_enumerator_next_files_async
函数,允许以块的形式异步加载文件。但是我怎么知道目录列表何时完成?这是我想出的代码示例:
static void add_file_callback(GObject *direnum,
GAsyncResult *result,
gpointer user_data){
GError *error = NULL;
GList *file_list = g_file_enumerator_next_files_finish(
G_FILE_ENUMERATOR(direnum),
result, &error);
if( file_list == NULL ){
g_critical("Unable to add files to list, error: %s", error->message);
}
GList *next;
GFileInfo *info;
GtkTreeIter iter;
DirList *list = (DirList*)user_data;
while(file_list){
...add file to list
}
}
int read_dir(const gchar *path, DirList *list){
g_assert(list != NULL && list->store != NULL);
GtkTreeIter iter;
gtk_list_store_clear(list->store);
list->path = path;
GFile *dir = g_file_new_for_path(path);
GFileEnumerator *dirent = g_file_enumerate_children(dir,
"*",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL,
NULL);
while( TRUE ){ /* <============================== When to end? */
g_file_enumerator_next_files_async(dirent,
BLOCK_SIZE,
G_PRIORITY_DEFAULT,
NULL,
add_file_callback,
list);
}
g_file_enumerator_close(dirent, NULL, NULL);
g_object_unref(dirent);
g_object_unref(dir);
return 0;
}
来自this g_file_enumerator_next_files_async
reference:
The callback can be called with less than
num_files
files in case of error or at the end of the enumerator.
因此,如果回调接收的文件数少于 BLOCK_SIZE
,那么您就知道出现错误或没有更多文件可用。
如果发生这种情况,请设置一个标志,供 read_dir
中的循环检查。
要执行列表,您应该递归调用 g_file_enumerator_next_files_async
,而不是循环调用它们,示例如下:
static void add_file_callback(GObject *direnum,
GAsyncResult *result,
gpointer user_data){
GError *error = NULL;
GList *file_list = g_file_enumerator_next_files_finish(
G_FILE_ENUMERATOR(direnum),
result, &error);
if( error ){
g_critical("Unable to add files to list, error: %s", error->message);
g_object_unref(direnum);
g_error_free(error);
return;
}else if( file_list == NULL ){
/* Done listing */
g_object_unref(direnum);
return;
}else{
GList *node = file_list;
GFileInfo *info;
GtkTreeIter iter;
while(node){
info = node->data;
node = node->next;
...add to store
g_object_unref(info);
}
g_file_enumerator_next_files_async(G_FILE_ENUMERATOR(direnum),
BLOCK_SIZE,
G_PRIORITY_LOW,
NULL,
add_file_callback,
list);
}
g_list_free(file_list);
}