c gtk +: загрузка текстового файла в TextBuffer GtkSourceView

Я пишу программу на языке C с gtk + и gtksourceview-2.0.

Я использую GtkFileChooser, чтобы пользователь мог выбрать файл, и когда он нажимает на него, я хочу, чтобы контент загружался в GtkSourceView 'TextBuffer

это функция, которая запускается, когда пользователь дважды щелкает файл в GtkFileChooser:

void on_file_activated(GtkWidget *widget, gpointer data) {
    GFile *file;
    FILE *fp;
    gchar *path_name;
    long file_size;
    gchararray file_buffer;
    file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(widget));
    path_name=g_file_get_path(file);
    g_debug("%s is chosen\n", path_name);
    fp=fopen(path_name, "r");
    g_assert( fp != NULL);
    fseek(fp, 0L, SEEK_END);
    file_size = ftell(fp);
    rewind(fp);
    g_debug("file size: %ld\n",file_size*sizeof(gchar));
    file_buffer=calloc(file_size, sizeof(gchar));
    g_assert(file_buffer != NULL);
    fread(&file_buffer,file_size,1,fp);
    g_debug("after fread");
    //file_buffer[file_size*sizeof(gchar)]=0;
    //g_debug("after adding zero: %s",file_buffer);
    gtk_text_buffer_set_text (textbuffer, file_buffer,2);
    g_debug("after set text");
    g_object_unref(file);
}

это результат моего приложения:

** (tour_de_gtk:18107): DEBUG: /home/ufk/Projects/gtk-projects/tour-de-gtk/Debug/src/examples/example_gtk_label/main.c is chosen

** (tour_de_gtk:18107): DEBUG: file size: 16

** (tour_de_gtk:18107): DEBUG: after fread 

после этого я получаю ошибку сегментации в команде gtk_text_buffer_set_text

как вы можете видеть, у меня есть две закомментированные команды. попытка g_debug буфера, которая, очевидно, создает ошибку сегментации, потому что я не добавил ноль в конец строки, и даже когда я пытаюсь добавить ноль в конец строки, я получаю ошибку сегментации. Я, наверное, что-то не так сделал.

здесь я пытаюсь записать только первые два символа буфера, но безуспешно.

Любые идеи?

Обновить

готовая функция:

void on_file_activated(GtkWidget *widget, gpointer data) {
GFile *file;
gchar *path_name;
long file_size;
gchar *file_buffer;
GError *error;
gboolean read_file_status;
file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(widget));
path_name=g_file_get_path(file);
g_debug("%s is chosen\n", path_name);
read_file_status=g_file_get_contents (path_name,&file_buffer,NULL, &error);

if (read_file_status == FALSE) {
    g_error("error opening file: %s\n",error && error->message ? error->message : "No Detail");
    return;
}
gtk_text_buffer_set_text (textbuffer, file_buffer,-1);
g_debug("after set text");
g_object_unref(file);
}

person ufk    schedule 20.02.2011    source источник


Ответы (1)


Здесь возможно множество улучшений, возможно, вы уже знаете о многих и просто возитесь с ними, но на всякий случай я перечислю несколько.

gchararray file_buffer;

Просто используйте char *

g_assert (fp! = NULL);

Следует использовать assert для ошибок программирования, а не ошибок времени выполнения, поэтому здесь g_printerr () или диалоговое окно было бы лучше

fseek (fp, 0L, SEEK_END); file_size = ftell (fp); размер_файла = ftell (fp); перемотка назад (fp);

fstat (fileno (fp), & statbuf), вероятно, лучший способ сделать это, но в целом подход плохой; вместо того, чтобы получать размер, лучше просто читать в динамически растущий буфер. Или, если вы хотите предварительно выделить весь буфер, просто используйте g_file_get_contents (). Другой подход - g_file_query_info () (который более переносим и использует vfs)

file_buffer = calloc (размер_файла, размер (gchar));

g_new0 (char, file_size) лучше, или g_malloc0 (file_size). Также вам понадобится file_size + 1, чтобы освободить место для нулевого байта.

fread (& file_buffer, размер_файла, 1, fp);

Здесь вам нужен file_buffer (символ *), а не & file_buffer (символ **). Вероятно, это настоящая причина немедленной поломки.

Вам также необходимо проверить возвращаемое значение fread ().

Здесь также отсутствует функция g_utf8_validate () для считываемых данных.

Взгляните на реализацию g_file_get_contents (), чтобы увидеть здесь один подход. Вы также можете использовать g_file_load_contents для использования GFile вместо пути (переносимый, использует vfs) или, что еще лучше, в реальном приложении, g_file_load_contents_async ().

Для отладки segfaults есть два лучших инструмента:

  • запустите gdb, дождитесь сбоя, затем введите «bt»; обязательно используйте -g с вашим компилятором при компиляции
  • запустите valgrind, посмотрите, где написано, что вы смотрите на плохую память
person Havoc P    schedule 20.02.2011
comment
Большое спасибо за полный ответ. Я новичок в gtk +, и это все еще меня смущает, каждый совет, который вы здесь написали, чрезвычайно важен для меня. собираюсь проверить ваши комментарии и вернуться к вам. - person ufk; 20.02.2011
comment
спасибо, я обновил свой основной пост последней функцией. я ценю все советы, которые вы дали. - person ufk; 20.02.2011
comment
Круто. вы, вероятно, все еще хотите использовать g_utf8_validate (), иначе вы можете получить сбой, если кто-то попытается открыть файл latin-1 или что-то в этом роде. - person Havoc P; 21.02.2011