Политика конфиденциальностиКонтактыО сайтеОтзывыGitHubDonate
© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB
ДТ
8 ноября 2018 г. 11:10

Чтение из большого файла

file

Проблема такая: одним из домашних заданий по программированию(первый курс) было написание блокнота. Т.е. ридера текстовых файлов. Это я, собственно, сделал, но есть небольшой нюанс - при открытии ОЧЕНЬ больших файлов (например, если в диалоговом окне выбора файла написать *.* , то можно будет, в обход запрету на разрешение файлов, открыть какой-нибудь блю-рей фильм на 30+ гб), программа погибает в агонии и с криками ( код ошибки : 3). Причем, если открывать нормальным блокнотом, что идет вместе с виндой, то он спокойно "переваривает" любой блю-рей. Каким образом это можно решить?

QFile file(QFileDialog::getOpenFileName(this,"Открыть файл","C:\\", tr("Текстовые файлы (*.txt);;Файлы C++ (*.cpp *.h)")));
        if (!file.open(QFile::ReadOnly | QFile::Text))
            return;
        QTextStream stream(&file);
        stream.setCodec("UTF-8");
        QString tempStr;
        while(!stream.atEnd())
            tempStr.append(stream.read(10000));
        ui->_mainTextField->setText(tempStr);
        MainWindow::setWindowTitle(file.fileName());
        fileName = file.fileName();
        tempStr = nullptr;
        file.flush();
        file.close();

6

Сдаётся мне, что у вас на ПК просто память кончается, а в обычном блокноте там каким-то способом реализована частичная подгрузка.

Просто QString tmpStr сам по себе не в состоянии съесть 30 гигабайт за раз, скорее всего падает в цикле while, надо проверять это момент, но наверняка там.

Тут вопрос в том, что вы хотите? Я бы сделал дополнительную проверку на тип файла и возможно размер и запретил бы открывать такой файл.


0
IF

Доброго времени суток.

Вы используете очень скользкий путь чтения файла(цикл пока не конец).

в цикле открывать файл на чтение и забирать по 10000 позиций - вот главная ошибка. А с кодом 3 он вылетает скорее всего потому что у вас оперативная память кончается - и идёт запрос на жёсткий диск, далее несколько больших запросов и ядро просит удалить данный процесс.


Евгений как всегда прав, что вам советует проверять на объём файла при считывании, и то что вы используете регулярные выражения для взятия файла - это скорее хак, который скорее всего можно как то попросить менеджер отключить( как всегда отправляю в документацию).


1
  • 8 ноября 2018 г. 18:47

Учитывая вышесказанное могу добавить,что необходимо читать из файла как минимум блоками,размером с буфер страницы,и выводить в текстовое поле виджета или как там у тебя реализовано по-блочно,ну и вообще надо полагать как минимум из аппаратных возможностей,если у тебя 4 гига ОЗУ,а ты пытаешься в него загрузить 30 GB,то эо не есть нормально.

0
ДТ

Чуть переписал код, программа, ожидаемо, перестала падать при открытии больших файлов. Но все равно зависает при попытке открыть хоть сколько-нибудь большой файл. А дожидаться открытия я уж не стал. Стыдно, на самом деле, что я сам не подумал о том, что скидывать всё в одну строку - глупо.

Хотя стандартный блокнот, опять же, довольно резво открыл экзешник на 900 мб, когда моя поделка попросту захлебнулась. Мне все еще интересно, каким образом это сделано там.


QString tempStr;
        ui->_mainTextField->clear();
        while(!stream.atEnd())
        {
            tempStr.append(stream.read(10000));
            if(tempStr.size() >= 100000)
            {
                ui->_mainTextField->append(tempStr);
                tempStr.clear();
            }
        }
        ui->_mainTextField->append(tempStr);
        changesIs = false; 

0

Думаю, что в блокноте частичная загрузка не в цикле, а по событию скролбара, вполне возможно, что он считывает необходимую информацию по мере прокрутки.

Как сайты подгружают контент по мере прокрутки страницы

1
IF

Доброго времени суток.


Евгений прав.


Вам надо перестроить приложение нарпимер по такой логике.


У вас есть поле - куда вы выводите содержимое текстового файла, рассчитываете сколько символов помещается на "данный момент" в окно.

Далее открываете файл на чтение и считываете сколько всего занимает данный файл - и выполняете "разметку скролбара".


Под "разметкой скролбара" приведу пример:

Например у вас есть файл, в нём 1000 символов, а в окно помещается 100, получается , что полоска скролбара дожна занимать на данный момент 100/1000 - 1/10 часть всего скролбара.


Далее вы выполняете отрисовку тех самый(из примера) 100 символов на сцену.


Евгений подчеркнул, что нужно увязать сигнал передвижения скролбара и слот перерисовки сцены.

При передвижении скролбара вы вычисляете верхнюю и нижнюю границу выводимую на экран текстового файла и запрашиваете в контейнер из файла - далее выводите на экран.

Воздможно улучшение например в качестве хэширования данных при запросе из файла - это ускорит приложение, но займёт чуть больше памяти при хранении данных - ЗА СЁ НУЖНО ПЛАТИТЬ.


Хорошего дня и удачи в кодинге.



2

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
v
17 января 2019 г. 11:51
vitalir12

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20баллов,
  • Очки рейтинга-10
v
17 января 2019 г. 11:49
vitalir12

C++ - Тест 002. Константы

  • Результат:50баллов,
  • Очки рейтинга-4
v
17 января 2019 г. 11:13
vitalir12

C++ - Тест 003. Условия и циклы

  • Результат:28баллов,
  • Очки рейтинга-10
Последние комментарии
I
16 января 2019 г. 8:06
IscanderChe

Заработало. Забыл model->select(); вписать.
I
16 января 2019 г. 8:02
IscanderChe

Всё равно пусто, хотя строка с данными в базу добавляется.
16 января 2019 г. 7:51
Евгений Легоцкой

потому, что нужно сохранять информацию для всех остальных ролей и столбцов через вызов переопределённого метода. Да к тому же вы ещё и зациклили вызов метода data. QVariant MySqlTableModel:...
I
16 января 2019 г. 7:43
IscanderChe

Сделал вот так. В tableView ничего нет, кроме заголовка. QVariant MySqlTableModel::data(const QModelIndex &index, int role) const{ if (role == Qt::DisplayRole) { QTime ...
Сейчас обсуждают на форуме
18 января 2019 г. 11:26
nayk1982

Для Desktop делал так: void pause(int ms){ QTimer timer; timer.setInterval( qBound(1, ms, 3600000) ); timer.setSingleShot(true); QEventLoop loop; QObject::connect(&...
17 января 2019 г. 12:01
Алексей Внуков

у меня просто есть отдельное поле с чекбоксамими какие колонки нужно отображать CheckBox { id: checkBox text: qsTr("some text") checked: true onC...
15 января 2019 г. 16:53
Михаиллл

Спасибо, заработало.Но выдало обычный текст без форатирования HTML.Придется искать дальше
15 января 2019 г. 12:52
BlinCT

Я же вам выше написал CLion умеет работать с ремоут машинами. И Qt так же собирает.
Присоединяйтесь к нам в социальных сетях

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы