Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как закрыть файл при закрытии приложения
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие
silver47
Приложение пишет лог в файл. Необходимо чтобы при закрытии приложения, собственно, этот лог сохранился. Не могу отловить событие закрытия
QObject::connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(appClose()));
. Деструктор тоже не выполняется. Может кто может помочь?

Спасибо.
abc
окну нужно присвоить флаг deleteOnClose, вроде так пишется, тогда деструктор выполнится
ещё
closeEvent - у твоего главного окна есть такая виртуальная функция
а ещё стоит сохранять лог периодически, потому что программа может завершиться аварийно
не вижу ничего плохого в том, чтобы с каждой записью открывать и закрывать файл
silver47
Цитата(abc @ 5.4.2011, 11:54) *
окну нужно присвоить флаг deleteOnClose, вроде так пишется, тогда деструктор выполнится
ещё
closeEvent - у твоего главного окна есть такая виртуальная функция
а ещё стоит сохранять лог периодически, потому что программа может завершиться аварийно
не вижу ничего плохого в том, чтобы с каждой записью открывать и закрывать файл


По поводу того, чтобы с каждой записью открывать и закрывать файл, сам только подумал и переделал уже. А вот про deleteOnClose, как присвоить его окну?
wiz29
QWidget* pWidget(new QWidget);
pWidget->setAttribute (Qt::WA_DeleteOnClose, true);

раз у тебя оконное приложение попробуй обработать сигнал от QApplication : void lastWindowClosed ().
silver47
Цитата(wiz29 @ 5.4.2011, 13:02) *
QWidget* pWidget(new QWidget);
pWidget->setAttribute (Qt::WA_DeleteOnClose, true);

раз у тебя оконное приложение попробуй обработать сигнал от QApplication : void lastWindowClosed ().


У меня оно не наследуется от QWidget. У меня нет окон - нечего закрывать.

Пока сделал так, чтобы файл с логом был всегда закрыт. открывается лишь на незначительное время для добавления записи, для решения задачи этого вполне достаточно. Но может все-же можно как-то понять, что твое приложение закрыли тем или иным образом? Вроде встречал на каком-то форуме, что платформонезависимо нельзя, но это касается только консольных приложений.
wiz29
можешь линкануть код функции main?

просто в любом случае одной обработкой сигнала от QCoreApplication нельзя отделаться.
silver47
Цитата(wiz29 @ 5.4.2011, 13:29) *
можешь линкануть код функции main?


main, в моем случае не делает ничего, кроме создания экземпляра класса и запуска лупа.
#include <QtCore/QCoreApplication>
#include <QTextCodec>
#include "mainapp.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    //***************************************************************
    QTextCodec *codec=QTextCodec::codecForName("UTF8");
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    //***************************************************************

    MainApp  aplication;

    QObject::connect(&aplication, SIGNAL(connectFailed()), &a, SLOT(quit()));

    return a.exec();
}
wiz29
объект "logger" синглтон в приложении?

если это так то все просто нужно немного модифицировать код твоего main и все будет в "шоколаде".
строку return a.exec(); поменяй на 2:
 int ret = a.exec();

 //закрыть логер

и вначале обязательно сделай переопределение стандартного обработчика "terminate handler function", это поможет тебе при завершении логера в случае непредвиденного завершения приложения. инфу можно посмотреть тут http://www.cplusplus.com/reference/std/exc.../set_terminate/
silver47
Цитата(wiz29 @ 5.4.2011, 13:50) *
объект "logger" синглтон в приложении?

если это так то все просто нужно немного модифицировать код твоего main и все будет в "шоколаде".
строку return a.exec(); поменяй на 2:
 int ret = a.exec();

 //закрыть логер

и вначале обязательно сделай переопределение стандартного обработчика "terminate handler function", это поможет тебе при завершении логера в случае непредвиденного завершения приложения. инфу можно посмотреть тут http://www.cplusplus.com/reference/std/exc.../set_terminate/


Простите. Совсем не понял. Объект "логгер" пишет в файл события, которые происходят при обработке данных другими классами, они кидают ему их посредством сигналов. Другие классы должны выполняться в лупе, то есть всегда, это не парсер чего-либо. Если они выполнили свою работу они уничтожаются, родительский класс создает новый объект, как только работа появиться. Надеюсь понятно объяснил.
abc
Wiz,
имеешь ввиду?
int res = a.exec();
file.close();
return res;

про terminate только на днях прочёл, оказывается, вот где можно использовать)
wiz29
Цитата(silver47 @ 5.4.2011, 12:02) *
Простите. Совсем не понял. Объект "логгер" пишет в файл события, которые происходят при обработке данных другими классами, они кидают ему их посредством сигналов. Другие классы должны выполняться в лупе, то есть всегда, это не парсер чего-либо. Если они выполнили свою работу они уничтожаются, родительский класс создает новый объект, как только работа появиться. Надеюсь понятно объяснил.

Невижу никаких проблем с тем чтобы ваш "логгер" был глобальным в приложении (даже если он потомок QObject) или же у вас есть некий общий файл в который все "сливается" с разных объектов (т.е. разделенный доступ к лог файлу)? (тогда здесь не все понятно с синхронизацией доступа к файлу).
p.s. Что конкретно не понятно? (синглтон - объект одиночка для всего приложения, в qt например, это QCoreApplication объект, как правило имеет метод instance() или нечто подобное)

кстати обработка сигнала aboutToQuit нормально работает только при корректном завершении приложения: вызовом метода QCoreApplication::instance()->quit(); в остальных случая код завершения не 0 и сигнал не генерится.
silver47
Логгер глобальный и один для всех объектов.

Конкретно не понятно как работает set_terminate.
По примеру мы устанавливаем метод, который будет вызываться в случае ненормального завершения программы. Это так? зачем тогда заменять a.exec(); на int res = a.exec();?

Если сделать все чисто по примеру, то вроде как не работает. Добавил консоль в сборку:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <QTextCodec>
#include "mainapp.h"

void abnormalExit(){
    std::cout << "Abnormal exit";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    //***************************************************************
    QTextCodec *codec=QTextCodec::codecForName("UTF8");
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    //***************************************************************

    MainApp  aplication;
    QObject::connect(&aplication, SIGNAL(connectFailed()), &a, SLOT(quit()));

    std::set_terminate(abnormalExit);
    return a.exec();
}


По Ctrl+C тихо закрывается. Ничего не оставляет после себя. Если вставить throw; до return a.exec() то исключение вызывает метод abnormalExit.
wiz29
1. менять не обязательно.
2. std::set_terminate работает следующим образом: если в какойто части программы возникает исключительная ситуация exception и данная ситуация не обработана ни одним перехватчиком искл. ситуаций то приложение аварийно завершается, перед своим завершением вызываться некая специальная глобальная функция terminate handler , собственно указатель на нее и устанавливает данный метод (это коротко , на "палцах") за более подробной инфой обратитесь к справочникам по C++. При закрытии консольного окна "через крестик" реально сам не смог отловить завершение.

Средставми Qt закрытие консоли с помощью Сtr + C или Alt + F4 скорее всего обработать не выйдет, придется писать платформозависимый код. (других путей пока не вижу)
Алексей1153
вообще говоря, достаточно просто всегда записывать данные в файл. Когда приложение умирает, система закрывает все дескрипторы, занятые приложением - файл автоматом закроется. По крайней мере в винде так :)
abc
Алексей, что происходит здесь?
http://www.forum.crossplatform.ru/index.php?showtopic=6720
Алексей1153
abc,

ну да, если что-то не успело записаться, то оно и не сохранится. А по топику в ссылке, навскидку:

вызывать flush после каждой записи - это гарантия перекидывания в файл из внутренних буферов. А close там ни при чём ИМХО

опять же, тонкости работы линукса я не знаю, а в винде файл просто закроется и ничего не потеряется из уже в него записанного :)
abc
я в винде компилировал, QString не пишется, QPixmap пишется... Как может не успеть записаться? дальше этих двух типов не проверял
Алексей1153
abc, а с flush тоже не пишется ?
abc
не пробовал, но если даже пишется, то вопрос изменится на - почему QString записать нужен flush, а QPixmap нет... :)
Алексей1153
abc, возможно, оператор << у них по разному устроен - в одном flush вызывается, в другом нет
abc
хмм, ладно, надо провести более качественные проверки для продолжения беседы)
silver47
Цитата(Алексей1153 @ 5.4.2011, 22:17) *
abc, а с flush тоже не пишется ?


В случае, если используется QTextStream для вывода в файл, то flush бесполезен.
void QTextStream::flush ()
Flushes any buffered data waiting to be written to the device.
If QTextStream operates on a string, this function does nothing.

Если писать в файл напрямую, не используя QTextStream, то QFile::flush решает проблему. Я ее все-же предпочел решить по другому - держать файл закрытым (в лог сыплются лишь сообщения об ошибках), теперь вопрос в другом, так сказать для общего развития: Как узнать что твое приложения прибили тем или иным способом? Как я понимаю платформонезависимо никак.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.