На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (2) 1 [2]  все  ( Перейти к последнему сообщению )  
> Перемешивание строк / Delphi/RAD XE4
    Цитата ^D^ima @
    Так в задании сказано что нельзя копироввть в память

    Насколько я понял, задание в #1 выделено жирным шрифтом, и там ничего не сказано о том, что можно, а что нельзя. Но у ТС это не первое задание на обработку текстовых файлов размером до 500-700 Мб, и все его попытки использовать TStringList в XE4 приводят к out of memory. Причина, надеюсь, всем понятна - удвоение занимаемой памяти при (тупом, и в данном случае совершенно ненужном) преобразовании AnsiString в юникод. Если бы стояла задача решить проблему только на уровне работы с файлами без их полной загрузки в память, то можно было бы сразу задать размер файла в 2 и более Гб. Но поскольку речь идет именно о 500-700 Мб, то это явно вопрос "на засыпку", который предполагает, что данную задачу можно решить и с загрузкой всего файла в память.
      Как вообще при наличии свопа может взбухать out of memory на жалких полтора гига? Тем паче что это не один кусок, а куча независимых строк.

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

      По сабжу:
      - первый проход - чтение построчно, сохранение для каждой строки смещений относительно начала файла
      - перемешивание - создание второго массива смещений, наполнение его рандомными элементами из первого массива. Либо проход по каждому элементу исходного массива и обмен значениями текущего элемента с рандомным
      - выдача результата - проход по перемешанному массиву, позиционирование+readln(f_src, s)+writeln(f_dst, s)
      Сообщение отредактировано: Fr0sT -
        Цитата Fr0sT @
        Как вообще при наличии свопа может взбухать out of memory на жалких полтора гига? Тем паче что это не один кусок, а куча независимых строк.

        Ты знаешь, как работает TStrings.LoadFromFile\Stream?
        В D7 весь файл читается в локальную переменную s:AnsiString и затем формируется список строк простым вызовом Strings.Text:=s. При размере файла до 700 Мб и более, это уже может вызвать проблемы в 32-битном приложении, т.к. из-за фрагментации адресного пространства (АП) может просто не оказаться непрерывного диапазона адресов такого размера (из-за некоторых дурных dll, норовящих загрузиться в середину АП).
        Но в современных XE это реализовано еще тупее - сначала весь файл читается в дин.массив TBytes, а затем вызовом TEncoding.GetString из этого массива формируется юникод-строка (удвоенного размера, если файл представлен в ANSI), которая затем используется для формирования списка тем же Strings.Text:=s. Сам понимаешь, что в 32 битном приложении два непрерывных куска памяти по 700 и 1400 Мб, плюс более 1400 Мб отдельных строк - уже ни в какие ворота не лезут. Отсюда и out of memory. И никакой своп тут ни при чем, т.к. просто\банально не хватает нужного адресного пространства.

        PS: Такая реализация прекрасно работает для текстовых файлов "нормального" размера. Поэтому это не тупость Борланда\Эмбаркадеро, а тупость тех, кто пытается использовать TStrings.LoadFromFile для текстовых файлов нереально большого размера.
          leo, да, про момент загрузки я забыл, каюсь. К сожалению, с покусочным чтением не стали заморачиваться (хотя Эмбы и не одни в этом - даже более специализированный редактор Akelpad тоже грешит таким неоптимальным механизмом).
          Связка TFileStream+TStreamReader (либо старый добрый Readln) поможет избежать перерасхода памяти
            Цитата Fr0sT @
            Связка TFileStream+TStreamReader (либо старый добрый Readln) поможет избежать перерасхода памяти

            В том-то и дело. По моему, эта задачка не школьно-учебная, а скорее тестовая\конкурсная. Да, можно ее решить универсально с индексацией строк файла и его повторным рандомным чтением. Но тут можно нарваться на ужасные тормоза при рандомном чтении файла (а можно и не нарваться, если винда при наличии свободной физ. памяти закэширует весь файл при первом чтении). Хотя 700 Мб (не одним куском, а в виде отдельных строк), это действительно не много, поэтому эту задачку можно решить и с загрузкой всех строк в память, но не на основе стандартного TStringList, а на основе TList или дин.массива AnsiString с блочным чтением файла (хоть тем же Readln, хотя для увеличения скорости и "крутизны" я бы добавил к нему SetTextBuf размером в 8-16 кБ).
            Сообщение отредактировано: leo -
              Друзья, тут
              https://stackoverflow.com/questions/2700790...arge-text-files

              предлагают использовать TStreamReader
              Я правильно понимаю что он считывает кусками, и ему не нужна память одним куском?

              Добавлено
              Т.е. можно просто в коде из первого поста поменять строку?
              Цитата Kirilis2018 @
              s.LoadFromFile('C:\text.txt');

              на
              ExpandedWrap disabled
                  AssignFile(F,'C:\text.txt');
                  Reset(F);
                    While not EOF(f) do
                      Begin
                        ReadLn(F,St);
                        s.Add(St);
                      End;
                  CloseFile(F);

              ?
                Цитата ^D^ima @
                предлагают использовать TStreamReader
                Я правильно понимаю что он считывает кусками, и ему не нужна память одним куском?

                Да. Судя по всему размер буфера по умолчанию составляет 4 Кб.

                PS: В принципе и у обычного TextFile есть буфер по умолчанию в 128 байт, который можно заменить на свой собственный любого размера через SetTextBuf.

                Цитата ^D^ima @
                Т.е. можно просто в коде из первого поста поменять строку?

                Можно, но в современных юникодных дельфях это будет приводить к бестолковому увеличению занимаемой памяти в 2 раза (если исходный файл в ANSI). Хотя 700*2 Мб (в виде отдельных строк, а не одним непрерывным блоком) должны выделяться без особых проблем.
                Но все же правильнее\лучше не расходовать попусту память и реализовать свой список или массив AnsiString на основе TList или динамического массива.
                  ^D^ima
                  Цитата ^D^ima @
                  предлагают использовать TStreamReader
                  Я правильно понимаю что он считывает кусками, и ему не нужна память одним куском?

                  Когда последний раз его изучал это было не так. Может и допилили.


                  leo
                  Цитата leo @
                  к бестолковому увеличению занимаемой памяти в 2 раза (если исходный файл в ANSI).

                  Пока современный дельфи моськой не ткнёшь он не конвертирует строки, а хранит в начале номер кодовой страницы.
                    Цитата leo @
                    Да, можно ее решить универсально с индексацией строк файла и его повторным рандомным чтением. Но тут можно нарваться на ужасные тормоза при рандомном чтении файла (а можно и не нарваться, если винда при наличии свободной физ. памяти закэширует весь файл при первом чтении).

                    Условия не озвучены, а значит, на тормоза пофиг...
                    Цитата ^D^ima @
                    Я правильно понимаю что он считывает кусками, и ему не нужна память одним куском?

                    Да. Именно для этого стримы и предназначены.
                    Цитата Pavia @
                    Пока современный дельфи моськой не ткнёшь он не конвертирует строки, а хранит в начале номер кодовой страницы.

                    Зависит от. Readln уже возвращает wide строку. Правда, возможно, есть и оверлоад вариант для ansi
                    Сообщение отредактировано: Fr0sT -
                      Цитата Pavia @
                      Пока современный дельфи моськой не ткнёшь он не конвертирует строки, а хранит в начале номер кодовой страницы.

                      Pavia, при всем уважении - либо ты не ту траву куришь (не те доки или блоги читаешь), либо говоришь о каких-то супер-пупер "современных дельфи", которых еще ни у кого нет ;)
                      Вот пришлось проверить твои заявления на недавней халявной D 10.1 Берлин-Хеми:
                      1) если читаем Readln в AnsiString, то ес-но и получаем AnsiString в однобайтовой кодировке;
                      2) если читаем просто в String, то также ес-но получаем юникод-строку с двухбайтовой кодировкой;
                      3) если добавляем AnsiString в TStringList, то она автоматом преобразуется в юникод с двухбайтовой кодировкой.

                      Ну и где тут "моська"? А-у-у? :jokingly:
                        Цитата Fr0sT @
                        Условия не озвучены, а значит, на тормоза пофиг...

                        Какой-то странный подход...
                        Ну и "Какой ты, нафиг, танкист?!"(С), ведь "Таких не берут в космонавты!" (С) :no:

                        В догонку к вопросу by ^D^ima из #21
                        Цитата ^D^ima @
                        Т.е. можно просто в коде из первого поста поменять строку?

                        По хорошему еще нужно:
                        1) Заменить тип St на AnsiString, а s с TStringList на дженерик TList<AnsiString>
                        2) Выделить буфер чтения Buf:array[0..4096*2-1] of byte и установить его через SetTextBuf сразу после Reset(F)
                        3) Я бы еще дополнительно задал TList.Capacity:=GetFileSize(TTextRec(F).Handle) div N, (где N = 8-16), чтобы не гонять попусту данные при последовательном наращивании длины массива указателей в TList.
                        Сообщение отредактировано: leo -
                          Цитата leo @
                          Какой-то странный подход...
                          Ну и "Какой ты, нафиг, танкист?!"(С), ведь "Таких не берут в космонавты!" (С) :no:

                          А смысл пузыриться оптимизировать, если задание учебное и в требованиях ничего не прописано?
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0383 ]   [ 16 queries used ]   [ Generated: 16.04.24, 08:58 GMT ]