Считал в память текстовый файл, разделение строк - 0D0A (CrLf). Подсчитал количество строк. Затем загнал файл в Word, а он показывает мне больше строк, чем я посчитал. Это я обмишурился, или Word? Подскажите, плиз. На маленьком файле вручную посчитал - совпадает, на большом - 240000 строк, Word показал 270000. А вручную подсчитать слабо. Гляньте опытным глазом кто-нить, пожалуйста. Код (Text): push esi xor ebx,ebx xor edx,edx mov ecx,FileSize ; размер mov dx,0A0Dh ; разделитель mov esi,ArrAddr ; начало push esi ; в стек, для последующего использования @Loop: cmp dx,word ptr[esi] jne @F inc ebx push esi ; адрес каждого разделителя - в стек @@: inc esi dec ecx jnz @Loop shl ebx,2 ; по количеству строк * 4 получаю кусок памяти mov PtrTblSize,ebx push PAGE_READWRITE push MEM_COMMIT push ebx push NULL Call VirtualAlloc mov PointerTbl,eax ; под таблицу указателей @@: pop dword ptr[eax+ebx]; и заполняю эту таблицу sub ebx,4 ; доставая указатели из стека jnz @B pop dword ptr[eax+ebx]; и в конце - указатель на начало pop esi Вот примерно так. И ещё 2 вопроса: 1. Можно ли ускорить работу цикла по поиску разделителей и вообще это методически правильный метод составления таблицы указателей? 2. Насколько нехорошо, что я засунул в стек 240000 двордов? В принципе, засунул и тут же высунул. Нигде не таскаю за собой. Отрабатывает довольно быстро, но всё-таки... Посоветуйте что-нибудь.
Вы считаете разделители, которые в ДОСе считаются разделителем строки, а в ВОРДе это конец параграфа. Возможно некоторые ДОС-овские строки не помещаются в ВОРД-овскую строку и переносятся на следующую строку. Вероятно так.
cresta Уж не собираешься ли ты сортировать файл по строкам? Ты знаешь, что в ntfs файлы могут иметь размер больше, чем 2^32-1? Посмотри реализацию функции memchr, например, в VC crt, файл memchr.asm.
pas прав - Word выдает "свое" количество строк, зависящее от установок параметров страницы. Еще возможные источники ошибки: 1) В "правильном" текстовом файле разделителем строк является сочетание 0D0A. Однако в самопальных файлах могут присутствовать и одиночные символы 0D или 0A, которые также считаются разделителем строки. Поэтому для надежности следует проверять три варианта: 0D, 0A и 0D0A (в частности такой анализ делается в TStrings.SetText от Borland) 2) В DOS-файлах может встречаться символ раздела страницы (код 0C,если не ошибаюсь). Считать его отдельной строкой или нет - вопрос. Что касается стека, то это тоже вопрос надежности. Надежнее, конечно, не возиться со стеком, а сразу работать с VirtualAlloc (MEM_RESERVE + MEM_COMMIT по необходимости) . Другой известный вариант - SparseArray (используется например в компоненте TStringGrid от Borland). Суть подхода в том, что указатели хранятся не в виде единого массива, а виде массива указателей на массивы (блоки) фиксированного размера (обычно кратного степени 2 для упрощения преобразования линейного индекса в номер блока и индекс элемента внутри блока).
pas Вполне ясно. leo В файле только 0d0a, это проверено. Тогда мне дважды надо пройти файл, один раз - получить кол-во строк (указателей), чтобы по этому кол-ву выделить память, и второй раз - собственно заполнение этой памяти адресами. Какие это даёт преимущества? Я должен пройти через массив в любом случае, и раз я это делаю, то заодно и сохраняю адреса строк. SparseArray тоже не сможет обойтись без первого прохода. И каков смысл сначала разложить адреса на составляющие (номер блока+смещение внутри блока), а затем выполнять обратное преобразование? В чём здесь фишка, я не понял. Я буду адресовать непосредственно как dword ptr[eax], а в случае с блоками надо ещё и вычислить значение, которое загрузить в eax. q_q Ну да, это моё любимое занятие Да и ntfs меня не пугает, я его стороной обойду. Не нашёл я у себя файла memchr.asm.
cresta да, это моё любимое занятие Если в файле строки не слишком длинные, то запускай sort.exe и используй ее результат. Не нашёл я у себя файла memchr.asm см. аттачь. Насколько нехорошо, что я засунул в стек 240000 двордов? Зачем? Тебе необходимо рисовать прогресс сортировки? Я делал так: Зарезервировал память для N адресов строк - массив адресов отсортированных строк. Адрес первой строки помещаю в начало массива. Читаю очередную строчку и методом половинного деления беру из массива адрес строки для сравнения с очередной. Как только нашел место очередной строки в массиве, то вставляю ее, все которые больше двигаются вниз. Разумеется, необходимо проверять не пора ли увеличить размер массива. Когда прочитаны все строки, то записываю результирующий файл согласно массиву. Ты используешь mmf? _1988072419__memchr.rar
в Word-е вообще 0Dh - это окончание параграфа, 0Ah для текста ничего не означает и пропускается От каких это, можно уточнить?
q_q, pas Ну, хорошо, есть у меня, например, длинное предложение (одно на абзац, например), как ваши установки могут привести к изменению этого кол-ва. Честно, перепробовал все (ну, кроме размера шрифта ) кол-во абзацев ну никак не поменялось. И не должно оно меняться он _установок листа_. По теме, загнал большой текстовый файл в ворд, кол-во символов абзаца (0d) в ворде (физическом файле) совпало с кол-вом 0d0a в текстовом файле, но оказалось немного больше того, как показала Статистика в ворде (не знаю, как оно там меряет). Хе-хе, между кол-вом символов в строке и кол-вом абзацев есть некоторая разница (в ворде, ес-но)
masquer длинное предложение (одно на абзац, например) ... перепробовал все ... кол-во абзацев ну никак не поменялось Не путай количество абзацев и количество строк. _373254595__count.gif
cresta > imho ничего страшного в этом нет, но нужно знать несколько моментов: http://www.wasm.ru/forum/index.php?action=vthread&forum=4&topic=5573 По ссылкам приведённым Four-F можно много интересного найти По поводу CrLf может попробовать, например, OpenOffece или другой редактор, Word imho глючный
а при чем здесь кол-во строк (а понял, это автор топика внес)? Если есть текстовый файл и в нем есть 0d0a, то в ворде это сконвертнется в 0d и будет считаться за абзац, а не строку
masquer при чем здесь кол-во строк Я так думаю, что автор смотрит именно на количество строк, не обращая внимания на количество абзацев.
Ну, для того, чтобы кол-во _строк_ подсчитать нужно действительно знать и размеры листа, и margins, и кучу параметров шрифта и пр. Если для текста, то хотя бы органичитель для длины строки. А так 0d0a это и будет абзац.
cresta Суть использования VirtualAlloc или SparseArray состоит именно в том, что не нужно заранее знать размер результирующего массива. Например, при использовании VirtualAlloc с флагом MEM_RESERVE можно сразу зарезервировать адресное пространство равное размеру файла (ну или 1/2,1/3 - хотя при резервировании это большой роли, не играет если речь не идет о гигабайтах,т.к. при этом никакой физической памяти не выделяется). Далее возможны два подхода. "Классический" - выделять память, используя MEM_COMMIT, блоками фиксированного размера: если после очередного inc индекс в ebx превышает размер выделенной памяти - выделяешь следующий блок по адресу BaseAddr+(ebx-1)*4. Другой подход - менее "элегантный" - сразу выделить достаточный размер памяти MEM_COMMIT. Если внимательно читать Win32.hlp, то увидим, что "The system initializes and loads each committed page into physical memory only at the first attempt to read or write to that page", т.е. пока мы не добрались до какой-то commited страницы - физической памяти она не занимает. В этом случае по завершении формирования массива делаем VirtalFree, освобождая лишнюю память. Суть использования SparseArray, также состоит в том, что мы пишем указатели в текущий блок, а когда он заполняется - выделяем новый и пишем в него. Ссылки на начало блоков хранятся в отдельном массиве. Конечно такой метод алгоритмически сложнее, чем VirtualAlloc. Но в отличие от последнего он не требует размещения всех блоков по последовательным адресам в памяти (sparse = разбросанный). Каждый блок может распределяться GlobalAlloc и лежать по произвольным адресам - где системе будет угодно. Конечно если ты загрузил массив в одной процедуре и все, то SparseArray никчему. А вот если к существующему массиву нужно добавить новый массив строк, то при обычном подходе нужно делать ReAlloc и переписвать кучу указателей, а в случае SparseArray - только указатели на блоки.
q_q Строки произвольной длины, до 2Гб. Если бы были фиксированной длины, то начало строки можно было бы просто рассчитать. А в случае переменной длины расчёт невозможен, поэтому составляю массив указателей на начала строк. Чтобы потом сортировать по указателям. Тогда надо будет немалое количество раз заниматься пересылками строк. С учетом возможной длины строк и их количества около 300 000 - Это время. А с указателями я исходный массив строк не трогаю, только сами указатели переставляю. После сортировки беру последовательно указатели и соответствующие им строки пихаю в новый кусок памяти, который выгружаю в файл. Т.е. пересылка строк - один раз, уже после сортировки. А может и этой пересылки строк можно будет избежать, если WriteFile позволит делать append. Надо будет глянуть. Не понял, Mail Message File что-ли? За аттач спасибо. S_T_A_S_ Единственная операция с загруженым стеком - вызов VirtualAlloc. И тут же разгрузил его. Мне кажется, коллизий типа исключений быть не должно. Неоднократно пробовал - вроде проблем не было.
q_q На больших массивах метод сортировки путем вставки очередной строки работает медленно из-за большого числа бестолковых пересылок. Гораздо лучше в плане быстродействия загрузить строки как есть, а затем использовать известный алгоритм QuickSort (опять же ссылаюсь на Borland Delphi или C Builder: TStringList.QuickSort). Работает гораздо быстрее.