Глава 7:Утилиты программиста
Выражение "сапожник без сапог" относится к профессионалу, не использующему собственные инструменты для облегчения своей работы. Программисты тоже люди. Им нужно извлечь пользу из используемой технологии и создать собственный инструментарий. Эта глава включает три инструмента, способные облегчить вам жизнь: построитель словаря данных, программу, изменяющую структуру файла данных по данным словаря без использования оболочки FoxPro, и программу исправления поврежденного файла, написанную с помощью замечательного специалиста в области восстановления данных Ли Хилларда из Себастополя, Калифорния.
Построение словаря данных
Вы разрабатываете продукт, способный осчастливить мир: еще один бухгалтерский пакет. Внезапно вы понимаете, что пропустили поле, которое должен иметь файл клиентов. Вы меняете структуру файла, делаете копию пустого файла и рассылаете заказчикам вместе с инструкцией на целую страницу. 97% из них позвонят вам в течение ближайших трех дней и вы потратите все свое время на объяснения. Десяток действительно скопирует файл в рабочий каталог и удалит основной файл не сделав страховочной копии. Что будете делать?
Не стреляйте в них, это противозаконно. Используйте программу DATADICT (Листинги 7-1...7-4) для построения словаря данных и поставляйте его вместе с вашей разработкой. Если вам понадобится изменить структуру файла, пошлите им новый словарь данных и скажите, чтобы они запустили программу DATAFIX, включенную в эту главу, для обновления файлов данных из своего приложения. Включите вызов программы в меню "Утилиты". Можете включить в обработчик ошибок режим, выводящий сообщение о необходимости запуска этой программы при получении сообщения об ошибке: "variable not found".
Листинг 7-1: Программа построения словаря данных для файлов текущего каталога
Листинг 7-2: Продолжение кода программы
Листинг 7-3: Продолжение кода программы
Листинг 7-4: Продолжение кода программы
Структура файла для словаря данных точно такая же как вы получаете при выполнении команды COPY STRUCTURE EXTENDED в FoxPro, кроме того, что вы добавляете имя файла для разделения данных о структурах различных файлов.
В Листинге 7-2 используется удобная функция ADIR(), создающая массив с именами всех .DBF-файлов в текущем каталоге. Это делается для того, чтобы программа не пыталась включить в обработку сам словарь данных и его рабочие файлы. Нужно отметить, что я мог бы использовать ADEL() для удаления ненужных имен из массива.
Программа в Листинге 7-4 создает индикатор прогресса обработки. Иногда мне звонят люди, желающие включить такой индикатор в операцию REINDEX. К сожалению, я не думаю, что вы сможете вклиниться в процесс перестройки индекса, хотя SET TALK ON | WINDOW <имя окна> вполне подходит для замены индикатора.
Я написал небольшой кусок кода, обеспечивающего проверку необходимости исправления файла, чтобы не заставлять пользователя вызывать утилиту восстановления файлов. Для этого я использовал команду SUM field_len TO hash_total и сравнивал результат со значением, хранящимся в .MEM-файле. Если величины отличаются или файла не существует, нужно запускать утилиту. Автоматический вызов таких операций служит для предотвращения ситуации, когда малограмотный пользователь откроет словарь данных и удалит все записи в нем, чтобы посмотреть на результат. Лучше дать им возможность выбирать режим из меню. В таком случае они будут знать, что происходит.
Использование словаря данных для сопровождения файлов заказчика Листинги 7-5...7-10 содержат текст программы, использующей словарь данных для сопровождения ваших файлов. Для обеспечения автоматического вызова используйте команду KEYBOARD [A] в вызывающей программе. Программа будет думать, что пользователь выбрал опцию All.
Листинг 7-5: Программа добавления или модификации структуры существующих файлов без потери данных
Листинг 7-6: Продолжение кода программы
Листинг 7-7: Продолжение кода программы
Листинг 7-8: Продолжение кода программы
Листинг 7-9: Продолжение кода программы
Листинг 7-10: Продолжение кода программы
В программе я вывожу в файл все имена всех полей, описанных в словаре данных. Единственный, пожалуй, трюк, который я применил - это учет смещения для экономии места. Любой файл может иметь 128 полей; файлов могут быть сотни. Вместо того, чтобы создавать массив типа DIMENSION fyle(200,128) я создаю одномерный массив. Если первый файл имеет пять полей, их имена попадают в первые пять строк, имя первого поля следующего файла находится в шестой строке. Все что мне нужно, это запомнить начальную позицию в массиве для каждого файла. Эта информация хранится в массиве Starts. Это немного сложно, но действительно снижает расход памяти.
Вначале мне нужно выяснить, какие файлы нуждаются в ремонте. Я копирую структуру файла в рабочий файл, привожу информацию о полях в табличную форму и проверяю на наличие расхождений. Изменение типа поля с численного на символьное может быть перехвачено на этом этапе, также как и изменение длины поля. Можете добавить новые имена полей. Изменения имен запрещены.
Код в Листинге 7-8 выполняет обработку. Обратите внимание, что я раньше проверил существует ли файл вообще. Процедура сравнения, создающая переменную differences, не запускается, если файл отсутствует.
Вначале я создаю страховочную копию. Я предпочитаю иметь возможность вернуться в исходное состояние. Если страховочная копия уже существует, программа выдает предупреждение.
В файл новой структуры я записываю старые данные. Именно поэтому вы не можете менять имена полей. Есть нехитрые способы записи данных в поля с измененными именами, но это не входит в задачу нашей программы. Кроме того, если вы меняете имена полей, то вряд ли обойдетесь только приведенной программой.
Я постарался написать как можно более стандартизированную программу. Она использует многочисленные макроподстановки и другие методы, позволяющие вашему коду работать в различных приложениях без изменений. Когда программа оценивает файл, она сравнивает действительное состояние вашего каталога с информацией, хранящейся в словаре данных Datadict.Dbf. Изменения внесены, и данные записаны. Процесс быстр и проходит безболезненно. Вам следует иметь достаточно свободного места на диске (больше чем занимает самый большой файл), я не проверяю этого (обычно место есть, обычно не используется и ничего не произойдет, если места не хватит).
Приведенная программа, будучи добавлена в ваше меню "Утилиты", облегчит модификацию структур файлов данных. Надеюсь, она вам понравится.
Ремонт поврежденных файлов данных
Способ использования файлов формата xBASE несет риск потери данных при выключении питания. Такое может произойти если кто-то зацепится за шнур и выдернет вилку из розетки. Тогда вы получаете сообщение "Not a database file" при попытке открыть файл данных. Существуют и другие ситуации, ведущие к повреждению файлов, после чего вы не получаете сообщение об ошибке, но тем не менее не можете работать с данными.
Программа, приведенная в Листинге 7-11(Программа исправления поврежденных заголовков файлов данных), решает подобные проблемы. Она была откомментирована и расширена Ли Хиллардом из Hillco Software, Sebastopol, California, за что я ему очень признателен. Инициализируем pick за пределами цикла DO WHILE (Листинг 7-12), что обеспечивает сохранение положения строки меню. Когда файл перезаписан, его положение в списке меняется, так как LoadList не располагает файлы по алфавиту. Процедура строит массив с именами файлов, полученный командой DIR FoxPro, и пользователь может видеть файл в списке (Листинг 7-13 (Функция вывода списка файлов))
При получении списка файлов вы видите экран.Меню в нижней части экрана позволяет пользователю выбрать одну из доступных функций. Функции View Directory и File Fix идентичны, кроме того, что View Directory не делает ничего при выходе из меню. Это способ просмотра таблицы данных, когда список слишком велик, чтобы уместиться на экране. Я использовал такой подход после того как увидел подобные вещи в PC Tools - матери всех утилит.
Если пользователь выбирает Fix a file, список открывается для прокрутки. Используя внутреннюю логику я ограничил реакцию программы в зависимости от того, что выбрал пользователь. Если текущая строка не является именем файла, я перехожу в цикл MENU, создавая впечатление, что ничего не случилось. Как видно из кода программы - все это трюк. Однако, создает хорошее впечатление.
Так как в каталоге может быть много файлов, меню позволяет прокручивать список. Нажмите Esc для выхода из окна. Если вы хотите исправить файл, который не поврежден, программа сообщит вам об этом и вернется к списку.
Если вы выбрали файл, отмеченный как поврежденный в списке выбора, программа считывает число записей, предположительно имеющихся в файле, выводит информацию из исправленного заголовка и выводит инидикатор прогресса.
Как только файл отремонтирован, программа обновляет экран для отражения изменившейся ситуации в списке. Вам может показаться интересным то, как это выполнено. Такой подход способен открыть новые возможности в организации меню. Если другая программа (или DOS) выдает нужный вам материал, направьте его в файл и используйте.
Еще программа имеет окно пояснений, вызываемое по нажатию F1. Я предпочитаю делать утилиты настолько простыми, что одного экрана с объяснениями оказывается достаточно. Правда, как вам подтвердят ребята из службы технической поддержки Fox Software, все равно никто не читает руководство.
Функции низкого уровня обладают замечательной мощностью, и я уверен, что программисты в будущем будут использовать их значительно шире.
Заключение
Программисты тоже пользователи. Они могут использовать инструменты, подобные приведенным в этой главе, для облегчения себе жизни и решения проблем, которые возникают с их собственными файлами. Используя функции низкого уровня доступа вы можете работать с любыми файлами, что откроет для вас целый мир новых возможностей.
Листинг 7-13
*!*****************************************************************
*!
*! Procedure: LOADLIST
*!
*!*****************************************************************
PROCEDURE loadlist * -- Build an array consisting of the .DBF display produced by the
* -- FoxPro DIR command, so that the trashed file display can be
* -- viewed by the user.
SET CONSOLE OFF
* Load the keyboard to keep from having to 'Press any key'
* with a large number of files. One CHR(13) for each 22 files
KEYBOARD CHR(13) + CHR(13) + CHR(13) + CHR(13)+ CHR(13) + CHR(13)
* Примечание: В последних версиях FoxPro поврежденные файлы не
* выдают сообщение об ошибке, и вы, возможно захотите использовать
* иной подход, например такой:
DIRECTORY TO FILE foxdir
CLEAR TYPEAHEAD && Remove any unused keystrokes
SET CONSOLE ON
fh = FOPEN( 'foxdir.txt')
FOR i = 1 TO 128
filelist( i ) = [ ] + LEFT( FGETS( fh ) , 43)
IF ( LEN( ALLTRIM( filelist( i ))) = 0 .AND. i > 2);
.OR. ( i = 127)
DIMENSION filelist(i-1)
EXIT
ENDIF
ENDFOR
RELE i
ON ERROR filelist(i)=LEFT(filelist(i),15)+[ - NOT A fox DATABASE]
FOR i=3 TO ALEN(filelist,1)
fname = ALLTRIM (LEFT(filelist(i),15))
USE (fname)
ENDFOR
USE
ON ERROR
FOR i=1 TO ALEN(filelist,1)
IF 'NOT A FOX' $ UPPER( filelist( i )) && Drop trailing chars
filelist( i ) = LEFT( filelist( i ) , 40) + SPACE(3)
ENDIF
ENDFOR
= FCLOSE( fh)
linecount = i - 1
onscreen = IIF( linecount <= 17, linecount, 17)
filelist( 1 ) = filelist( 2 )
filelist( 2 ) = REPLICATE( [-], 44)
@ 3, 3, 3 + onscreen + 1, 3 + 45 BOX [+-+¦+-+¦ ]
FOR i = 1 TO onscreen
@ 3 + i, 4 SAY filelist( i )
ENDFOR
RETURN
* Любой файл, который невозможно открыть будет отмечен как испорченный
* EOP: LoadList
RETURN
* EOP: LoadList
*!*****************************************************************
*!
*! Procedure: OK2GO_ON
*!
*!*****************************************************************
PROCEDURE ok2go_on
PRIVATE ovr_wrt
ACTIVATE WINDOW okay
CLEAR
@ 0, 1 SAY "File " + oldname + " already exists."
@ 1, 5 PROMPT " Cancel "
@ 1, COL() + 1 PROMPT " Proceed "
ovr_wrt = 1
MENU TO ovr_wrt
DEACTIVATE WINDOW okay
IF ovr_wrt <> 2
RETURN .F.
ENDIF
DELETE FILE &oldname
RETURN .T.
* EOP: Ok2Go_On
*!*****************************************************************
*!
*! Procedure: FIXHELP
*!
*!*****************************************************************
PROCEDURE fixhelp
ACTIVATE WINDOW fixhelp
CLEAR
TEXT
pinter FOXPRO letter FILE fixer
-------------------------------
this PROGRAM will RESTORE ACCESS TO FILES that FOXPRO has marked
'Not a Fox database'. it works IN the SAME way that the norton
utilities(tm) filefix PROGRAM works.
IF FOXPRO reports that A FILE is 'Not a Fox database', RUN this
PROGRAM AND pick the FILE IN question FROM the FILE list. the DATA
will be copied TO A new FILE first. then, your original FILE will
be renamed TO <filename>.old, AND the FIXED FILE will be renamed
TO the PRODUCTION FILE name.
IF you've already got a file named <filename>.OLD, the program
won't proceed unless you tell it to delete the file. If you want to
SAVE your .old FILE, RENAME it TO something ELSE, then RUN filefix.
-------------------------------------------------------------------
po BOX 1324 • menlo park, ca 94026-1324 • (415) 325-7953
ENDTEXT
WAIT WINDOW
DEACTIVATE WINDOW fixhelp
RETURN