oldi

Технология разработки приложений: практический пример на VB

Часть 1

Алексей Малинин

Мы строим свои системы так же,
как братья Райт строили свои самолеты:
создаем всю систему целиком, запускаем ее
— пусть она развалится! — и начинаем все сначала.

 

Проф. Грехем, сборник Software Engineering, 1970 г.

Постановка задачи

Этап 1: копирование и перекодировка файлов по заданному списку

Этап 2: модификация имен каталогов и ведение протокола работы

Этап 3: перекодировка файлов

Заключение

 

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

Точнее, принцип этой технологии заключается в пошаговой реализации проекта, опирающейся на следующие основные положения:

  1. Использование методики «снисходящего проектирования» (другие названия: «пошаговое совершенствование», «иерархическое») — от компонентов приложения верхнего уровня к компонентам нижнего уровня.
  2. Пошаговая разработка. На каждом шаге выполняется тестирование созданного программного фрагмента. Фрагмент проверяется не только в рамках работы всей программы, но и в случае необходимости — с использованием специальных текстовых конструкций. Последнее необходимо, если функциональность созданного кода не полностью задействована в рамках данной конкретной программы.
  3. Делая шаг, нужно иметь в виду следующий, а может быть и еще один (так, проходя трассу слалома, горнолыжник должен видеть сразу несколько ворот вперед и думать, как он пройдет вторые, а не первые ворота).
  4. Одна из ключевых идей — максимально быстрое создание работающего варианта приложения, выполняющего хотя бы одну полезную для пользователя функцию. Далее наращивайте функциональность приложения исходя из соображений практической потребности в них и скорости реализации.
  5. Качественное оформление программы по ходу работы (присвоение наименований переменным, комментарии, отступы и т.д.).
  6. Оперативное выделение в ходе разработки категории «повторно используемых» компонентов, формирование набора таких компонентов (этот вопрос мы будем рассматривать во второй части статьи).

В статье показано, что использование правильной методики позволяет при высокой скорости разработки поучать эффективные решения. Кроме того, при такой работе «с колес» можно добиться минимальных потерь в виде «ненужного» кода (кода, который был написан, но впоследствии удален за ненадобностью).

Здесь мы будем говорить о разработке локального, небольшого приложения. Разумеется, для создания даже средних систем этап «бумажной» прорисовки проекта является необходимым, и его качество в решающей степени определяет будущий результат. Однако при внимательном изучении вопроса легко увидеть, что многие приведенные выше положения вполне годятся и для создания крупных проектов. Просто там под «шагом» будут подразумеваться не десять строк кода, а другие, более объемные компоненты проекта.

Постановка задачи

Задача связана с процедурой поддержки (обновления) моего персонального Web-узла. Хотелось бы сразу предупредить, что я — довольно неопытный Web-мастер и поэтому, вполне вероятно, даже не догадываюсь о существовании готовых средств решения задач, о которых пойдет речь далее. Но, во-первых, в данном случае мы обсуждаем вопрос технологии разработки программ, а не инструменты работы с Web. А во-вторых, даже если мы «изобретем велосипед», созданное нами приложение может оказаться полезным для реализации аналогичных задач.

Работаю я со своим Web-сервером следующим образом: его разработку я веду на персональном компьютере в каталоге MySourceWebSite, а пользователи Интернета имеют дело с его копией, находящейся на каком-то удаленном сервере с именем http://www.visual.2000.ru/. Периодически производится обновление содержимого сервера: сначала я выполняю все операции с файлами в каталоге MySourceWebSite, а потом переписываю обновления на http://www.visual.2000.ru/ с помощью FTP-клиента.

Проблема перезаписи заключается в том, что на локальном компьютере я работаю с файлами в кодировке Windows-1251, а на Web-сервере они должны существовать в кодировке KOI-8 (сохраняя при этом строку <Meta charset=windows-1251>). Это выглядит довольно странно, однако таковы были указания Web-провайдера, а проведенные мною различные эксперименты подтвердили их правильность.

Поскольку мой FTP-клиент не умеет перекодировать файлы в момент перезаписи, я вынужден держать у себя также копию Web-сайта в кодировке KOI-8 в подкаталоге MyKoi8WebSite. В результате процедура перезаписи обновлений может быть представлена в виде следующих шагов:

  1. В первую очередь определяю список файлов, которые нужно переписать на Web-узел. Это выполняется с помощью операции Find в Windows Explorer с поиском по дате. Обычно число обновленных файлов составляет 10-20. Читать этот список с экрана не очень удобно, поэтому я вручную переписываю его на лист бумаги (я не нашел возможности импорта списка в виде файла или вывода на печать, хотя, утилиты, которые могут это делать, безусловно, существуют).
  2. Открыв два окна Windows Explorer, выполняю копирование файлов из MySourceWebSite в MyKOI8WebSite.
  3. С помощью утилиты Coder перекодирую (по переписанному мною списку) файлы в MyKOI8WebSite из Windows-1251в KOI-8.
  4. Соединяюсь с Web-сервером и с помощью FTP-клиента копирую туда файлы из MyKOI8WebSite.

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

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

Думаю, гораздо лучше выглядел бы следующий вариант: вызвал утилиту, указал в окошке дату начала обновления и нажал кнопку «Переписать файлы из MySourceWebSite». И потом только смотри, как утилита соединилась с удаленным FTP-сервером, провела авторизацию, начала копировать только нужные файлы, одновременно выполняя их перекодировку, и в конце выдала отчет о проделанной работе.

Вот и попробуем создать такое приложение. Честно говоря, не уверен, что мне удастся реализовать этот план до конца, хотя бы потому, что я никогда не имел дело с программированием FTP-доступа.

Обращаю внимание читателей на следующий момент: этот текст будет точно отражать весь ход реализации проекта. В момент написания этой фразы у меня нет никаких заготовок, и поэтому мы начнем с запуска VB 6.0 и выбора опции New File.

В начало

В начало

Этап 1: копирование и перекодировка файлов по заданному списку

Замечание 1. Перед началом работы убедитесь, что в среде VB (окно Options) у вас установлены режимы Require Variable Definition (Обязательное объявление переменных) и Save Changes (Сохранение изменения проекта при каждом запуске). Если вы все же хотите иметь возможность отката к неким предыдущим версиями проекта, стоит подумать об использовании системы управления версиями, например Visual SourceSafe. Советую также сбросить флажок Compile on Demand.

Сразу  сохраните проект, чтобы указать местоположение его файлов. Это должен быть каталог, отличный от того, где находится Visual Basic. Используйте режим Require Variable Definition (Обязательное объявление переменных) и Save Changes (Сохранение изменения проекта при каждом запуске).

 

Шаг 1. Создаем новый проект Standard Exe. Сразу же меняем стандартные имена Project1 и Form1 на какие-либо осмысленные названия, в данном случае CopyKoi8 и frmCopy8. Устанавливаем свойство Caption формы как «Преобразование из Win в KOI8». Запустите созданный проект на выполнение и запишите его модули в соответствующий каталог.

 

Замечание 2. Первый запуск с «пустым» проектом нужен для того, чтобы определиться с местом, где он будет храниться. По умолчанию будет предложен каталог, в котором находится сам VB. Ни в коем случае не записывайте туда свой проект! Для хранения своих проектов и данных заведите отдельный каталог (а для каждого проекта — подкаталог). Отдельный каталог нужно сделать для хранения повторно используемых компонентов.

Правильнее всего разбить жесткий диск на два (или больше) логических диска. Один диск (С:) можно использовать для хранения операционной системы, другой (D:) — для записываемых приложений (Office, VB и пр.), третий — для хранения создаваемых файлов (проектов, документов, почтовых сообщений и пр.). За счет этого существенно повышается надежность хранения информации. Понятно, что резервная копия будет делатьcя простым копированием только диска E:, так как в случае краха системы и систему, и приложения можно восстановить с дистрибутивов. Самая ценная информация — созданная именно вами.

Замечание 3. В случае применения для форм и элементов управления неких осмысленных имен (свойство Name) вместо стандартных (что очень рекомендуется), их нужно устанавливать сразу после создания соответствующих объектов и желательно не менять в дальнейшем. Дело в том, что при замене имени объекта, например с Text1 на txtFileName, имена всех созданных ранее событийных процедур Text1_ХХХ. и ссылки на Text1 нужно менять вручную. Если вам все же придется корректировать имена уже задействованных объектов и переменных, стоит воспользоваться командой Replace для просмотра всех модулей проекта.

 

Шаг 2. Теперь разместим элементы управления, которые нужны нам для начала работы. Пока представляется необходимым иметь элементы, размещение которых на форме приведено на рис. 1:

 

Тип элемента Свойство Name Примечание
Label lblFrom Имя главного каталога, откуда будут копироваться файлы
Label lblTo Имя главного каталога, куда будут копироваться файлы
Label lblCopy Число файлов, скопированных без перекодировки
Label lblConv Число файлов, скопированных с перекодировкой
Label lblReplace Число измененных файлов (ранее существовавших)
Command cmdCopy Команда на выполнение копирования (необходимость перекодировки будет определяться автоматически по расширению файла.)
Command cmdExit Команда на завершение утилиты
DirListBox dirList Окно для выбора каталога
FileListBox filList Список файлов выбранного каталога

 

Несколько примечаний:

  1. Пока будем работать с жестко заданными именами каталогов (откуда и куда копируются файлы). Лично мне этого вполне достаточно. Потом реализуем возможность выбора каталогов.
  2. Для удобства ориентации на форме установим для меток Caption = Name (при запуске программы нужные значения устанавливаются программно).

Теперь сформируем программный код для данного шага отладки:

Dim PathFrom$, PathTo$  ' имена каталогов ОТКУДА и КУДА
' счетчики скопированных, перекодированных и замененных файлов
Dim CopyCount&, ConvCount&, ReplaceCount&  
   
Private Sub Form_Load()  
    ' Начальная настройка
    ' Имена каталогов Откуда и Куда
    PathFrom = "d:\my-sites\visualmy\"  
    PathTo = "e:\dreamwear\visual\"  
      ' Установка свойств
    lblFrom.Caption = "Откуда: " + PathFrom
    lblTo.Caption = "Куда:   " + PathTo  
    ' обнуление счетчиков  
    CopyCount = 0: ConvCount = 0: ReplaceCount = 0  
    Call CountCaption  ' названия меток со счетчиками
      ' начальная установка каталога ОТКУДА
    dirList.Path = PathFrom$  
    filList.Path = dirList.Path  
    filList.Pattern = "*.*"  ' все файлы в каталоге
End Sub  
Public Sub CountCaption() 
  ' вывод содержимого счетчиков
  lblCopy.Caption = "Скопировано файлов    = " & CopyCount
  lblConv.Caption = "Перекодировано файлов = " & ConvCount
  lblReplace.Caption = "Заменено файлов = " & ReplaceCount  
End Sub  
   
Private Sub cmdExit_Click()  
  Unload Me   ' завершить работу
End Sub  
   
Private Sub Form_Unload(Cancel As Integer)  
    MsgBox "Конец работы"
End Sub

Несколько примечаний:

  1. Сейчас довольно часто не проводят начальной установки переменных, считая, что эта операция уже выполнена в момент компиляции.  Тем не менее программное обнуление счетчиков я сделал, так как это способствует лучшему восприятию программы и гарантирует от возможных неприятностей. А вдруг вы потом захотите объявить переменные статическими и использовать форму в виде компонента другого приложения?
  2. Я сразу выделил установку меток со значениями счетчиков в отдельную процедуру, так как очевидно, что такая операция понадобится впоследствии и при перезаписи файлов.
  3. Процедура Form_Unload содержит не очень нужный в данный момент вывод сообщения. Этим я хочу подчеркнуть, что данная процедура нам понадобится в дальнейшем: код, который нужно будет выполнить при завершении утилиты (а он скорее всего появится), необходимо записать именно здесь, а не в cmdExit_Click. Ведь закрыть форму можно и путем нажатия системной кнопки Close.
  4. По ходу отладки утилиты мы будем использовать вывод информации с помощью MsgBox. После проверки фрагментов кода будем исключать их, превращая в комментарии. Не стоит сразу удалять эти строки — они могут пригодиться в будущем, к тому же они хорошо показывают ход отладки приложения.

Запустите проект и убедитесь, что все названия меток сфомированы верно.

 

Шаг 3. Займемся элементом управления dirList (DirListBox — выбор каталога). Для начала проверим, в каком виде выдается имя каталога. Напишем такой код:

Private Sub dirList_Change()  
   MsgBox dirList.Path  
End Sub  

Запустите проект и посмотрите, что выдается для корневого каталога и подкаталогов.

 

Замечание 4. При работе с именами каталогов следует учитывать возможности их двоякого обозначения: как с обратной косой чертой в конце имени, так и без нее, что создает определенную путаницу и может стать причиной ошибок. Рассмотрим это на примере элемента управления DirListBox:

Print DirListBox.Path  'для корневого каталога черта всегда  
           'выдается (C:\), для всех остальных — нет (C:\TMP).  
DirListBox.Path = "C:\TMP"  
DirListBox.Path = "C:\TMP\"  'правильно работают оба варианта  
   
DirListBox.Path = "C:\"  ' будет установлен каталог C:\  
DirListBox.Path = "C:"  ' будет установлен ТЕКУЩИЙ каталог   
                        'диска C: (например C:\Winodws)  

Итак, мы увидели, что:

а) правильно задали начальное имя каталога PathFrom;

б) текущее имя не содержит косой черты в конце.

 

Внимание! Чтобы избежать проблем с формированием полных имен файлов, всегда будем задавать в переменных PathFrom и PathTo идентификаторы с косой чертой в конце.

 

Теперь изменим код следующим образом:

Private Sub dirList_Change()  
   'MsgBox dirList.Path
   ' проверка на допустимость имени каталога
   If InStr(dirList.Path, Left(PathFrom, Len(PathFrom) - 1)) <> 1 Then  
     MsgBox “Вышли за пределы заданного каталога!”
     dirList.Path = PathFrom ' принудительная установка
   End If
   filList.Path = dirList.Path ' текущий каталог для списка файлов
End Sub

Передвигаться от заданного главного каталога можно вниз по дереву, но вверх попадать нельзя. Для этого нужна реализованная выше проверка.

 

Запустите проект и убедитесь, что созданная проверка действительно правильно работает. Убедитесь, что смена списка каталогов в элементе filList выполняется верно.

 

Шаг 4. Теперь приступим к реализации процедуры копирования перекодировки файла. Она будет выполняться либо нажатием кнопки «Копировать+Перекодировать», либо двойным щелчком по имени файла в списке. Для начала напишем такой код:

Private Sub filList_DblClick()  
  Call cmdCopy_Click  
End Sub  
   
Private Sub cmdCopy_Click()  
  ' Копирование и перекодирование файла
  '
  Dim FileFrom$, FileTo$ ' имена исходного и результирующего файлов
   
  MsgBox filList.FileName  ' в каком виде выдается имя файла?
  FileFrom = filList.FileName   
  If FileFrom = "" Then  
    MsgBox "Не выбран файл!": Exit Sub
  End If
  ' далее пойдет код дальнейшей обработки
End Sub

Несколько примечаний:

  1. Мы поставили MsgBox, чтобы проверить, в каком виде выдается имя файла. Под именем файла можно подразумевать как идентификатор внутри каталога, так и идентификатор, включающий полный путь к файлу. Некоторые элементы управления имеют свойства для обоих вариантов, FileListBox работает только с первым.
  2. Далее следует проверка на тот случай, когда в списке нет выделения, а пользователь щелкнет кнопку.

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

 

Шаг 5. Далее мы будем дописывать процедуру cmdCopy_Click, чтобы выполнить операции копирования и перекодировки файла.  Допишем внизу такой код для формирования полного имени исходного и результирующего файлов:

  Dim a$, i%  
  If Right(filList.Path, 1) <> "\" Then a$ = "\" Else a$ = ""  
  FileFrom = filList.Path + a$ + FileFrom  
  FileTo = PathTo + Mid$(FileFrom, Len(PathFrom) + 1)  
  MsgBox FileFrom & vbCrLf & FileTo  

Здесь мы подстраховались на случай, если кто-то в качестве исходного каталога будет задавать корневой.

Внимание! В нашей утилите мы не предусматриваем случаи, когда в каталоге КУДА нужно создавать новые подкаталоги. В будущем такую возможность можно реализовать, причем это легко сделать вручную, поскольку новые разделы Web-узла создаются достаточно редко.

 

Запустите проект для разных значений PathFrom и PathTo. Введенные ранее значения можно закомментировать и попробовать разные сочетания имен типа C:\ и C:\TMP\. Убедитесь, что имена файлов всегда формируются правильно. 

 

Шаг 6. Следует различать две ситуации: создание нового результирующего файла и замена уже существовавшего. Для этого допишем далее следующий код:

  Dim sReplace$
  If Dir(FileTo) <> "" Then ' результирующий файл уже существует
    If vbYes = MsgBox("Удалить существующий файл " & FileTo & " ?", _
       vbYesNo, "Удалить?") Then  ' удалить
       Kill FileTo: sReplace = " Замена"  
       ReplaceCount = ReplaceCount + 1  ' счетчик замененных файлов  
    Else: Exit Sub  
    End If  
  Else: sReplace = " Новый"  
  End If

Несколько примечаний:

  1. В окончательном варианте запрос на замену существующего файла можно будет при желании убрать либо предусмотреть опцию — спрашивать подтверждение или нет. Хотя при перезаписи текстовых файлов уже существующий файл автоматически удаляется, предпочтительнее сделать операцию удаления в явном виде.
  2. В окончательном варианте мы обязательно создадим протокол нашей работы, где будем для каждого файла указывать, осуществлялась ли замена (для этого формируем переменную sReplace).

Внимание! Теперь начинаем экспериментировать с процедурами удаления и копирования файлов в каталоге КУДА. Для этого создадим временный файл для тестирования, например E:\MyTest\, и это имя пока запишем для установки переменной PathTo. Скопируем туда несколько файлов из исходного каталога.

Запустите проект и убедитесь, что программа правильно определяет наличие уже существующих файлов и при соответствующем ответе пользователя удаляет его.

 

Шаг 7. Теперь напишем код для копирования файлов в конец процедуры cmdCopy_Click:

   Dim FileExt$, sCopy$, lnFrom%, lnTo%  
   
   FileExt$ = Right$(FileFrom, 4)  ' расширение файла  
   If FileExt$ = "****" Then ' такое условие никогда не выполнится
   '   If FileExt$ = ".txt" Or FileExt$ = ".htm" Then  
    'перекодирование + копирование
    ConvCount = ConvCount + 1
    sCopy = " Перекодирован Win -> KOI8"
   Else  ' только копирование
    ' открыть файлы  
    lnFrom = FreeFile: Open FileFrom For Binary As #lnFrom  
    lnTo = FreeFile: Open FileTo For Binary As #lnTo  
     'копирование содержимого  
    ReDim Buffer(1 To LOF(lnFrom)) As Byte  
    Get #lnFrom, , Buffer()  ' читаем полностью
    Put #lnTo, , Buffer()    ' записываем полностью
    CopyCount = CopyCount + 1  'счетчик скопированных
    sCopy = " Скопирован"   
  End If  
  Close #lnFrom: Close #lnTo  
  ' обновление счетчиков на форме
  Call CountCaption

Несколько примечаний:

  1. Чтобы не заниматься контролем за распределением номеров для разных операций, используем динамическое определение логических номеров файлов (это не последние файлы, с которыми будет работать наша программа). Обратите внимание, что получение свободного логического номера должно выполняться непосредственно перед операцией открытия файла. Следующая конструкция будет неработоспособной:
    lnFrom = FreeFile: lnTo = FreeFile  'обе переменные получили одинаковое значение  
    Open FileFrom For Binary As #lnFrom  
    Open FileTo For Binary As #lnTo  
  1. Пока продолжаем развитие нашей утилиты только для случая простого копирования файлов. Однако уже сейчас мы вставили конструкцию If ... Then ... Else... End If, чтобы подчеркнуть, что есть некий общий код для обоих случаев и что нужно выполнять некоторые парные операции (например, изменять счетчики и формировать переменную sCopy). Хотя в часть «перекодировать» мы сейчас не попадаем, тем не менее в комментарии уже указали, что операция будет выполняться для TXT- и HTM- файлов.

Запустите проект и убедитесь, что программа правильно производит копирование файлов, предупреждая об уже существующих файлах и верно изменяя счетчики. Попробуйте скопировать файл из подкаталога, которого нет в каталоге КУДА, — должна появиться ошибка с сообщением Path not found (Не найден путь).

 

Такая ситуация будет встречаться редко, но лучше ее обработать программным путем, без аварийного завершения утилиты. В начало процедуры cmdCopy_Click запишем:

On Error GoTo RathNotFound  

а в самый ее конец:

  Exit Sub
  RathNotFound:  ' обработка ошибки
  MyError = Err  
  If MyError = 76 Then   
    If MsgBox("Нельзя создать файл " & FileTo, _
      vbRetryCancel, "Нет такого каталога!") _
        = vbRetry Then Resume ' повторить попытку
  Else  ' какая-то другая ошибка
    MsgBox "Ошибка = " & MyError  
  End If  

Мы решили программно не создавать несуществующие каталоги, так как подобная необходимость появляется довольно редко. Но стоит обратить внимание на то, что в момент получения такого предупреждения пользователь может, не прерывая выполнение утилиты, создать каталог с помощью проводника, а затем повторить попытку записи файла, нажав кнопку Retry.

 

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

 

Итак, мы создали полезную утилиту CopyKoi8, которая позволяет копировать произвольные файлы из одного каталога в другой, сохраняя структуру внутренних подкаталогов.Таким образом, мы существенно упростили операции пункта 2 исходной задачи.

 

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

Более того, в дальнейшем мы создадим более «автоматические» процедуры копирования и преобразования, хотя и данный режим ручного выбора файлов будет нам иногда необходим.  Мы реализовали наиболее общий случай, причем сформированный нами код на 90% пригодится и для других режимов работы.

Теперь можно передать созданную утилиту для эксплуатации пользователю (себе самому) и приступить к ее дальнейшему функциональному развитию.

В начало

В начало

Этап 2: модификация имен каталогов и ведение протокола работы

В каком направлении развивать наш проект? Здесь просматриваются следующие варианты:

  1. Провести преобразование кодировки текстовых файлов.
  2. Обеспечить ведение протокола работы.
  3. Выполнить автоматическую выборку файлов по дате.
  4. Предоставить пользователю возможность задавать имена каталогов ОТКУДА и КУДА.
  5. Кое-что еще...

Мой подход таков: следует сделать то, что реализуется быстрее всего и в то же время необходимо для работы. Для перекодировки файлов по крайней мере нужны кодовые таблицы Windows-1251 и KOI-8. Автоматическая выборка файла по дате — дело тоже не очень простое. К тому же без ведения протокола она проста не нужна. Итак, решено — ввод имен каталогов и протокол работы.

 

Шаг 8. Ввод имен каталогов, создание INI-файла  проекта.

Казалось бы, самый простой вариант — использовать текстовые поля для имен каталогов. Можно также сделать специальные процедуры для выбора каталогов с помощью диалоговых окон. Все это будет выглядеть эффектно, но для реальной работы ни один вариант не годится. Во-первых, выбор каталогов должен производиться только в самом начале, при запуске утилиты (изменение их в процессе работы нужно просто запретить). Во-вторых, на конкретном компьютере имеется лишь фиксированная пара каталогов для подобного копирования. Поэтому менять каталоги следует только один раз — при установке утилиты на компьютер или при смене каталогов (ведь речь-то идет о копии Web-сайта!).

Итак, сейчас мы выбираем самое простое решение: пусть тот, кому не нравятся наши «зашитые» имена файлов, использует для их начального определения текстовый файл CopyKoi8.INI, который должен быть записан в том же каталоге, что и сама утилита.

 

Для этого в процедуре Form_Load заменим две строки с начальным формированием переменных PathFrom и PathTo на обращение к процедуре:

  Call InputIniFile  

Затем напишем саму процедуру:

Public Sub InputIniFile()  
  'Инициализация переменных утилиты CopyKoi8
  Dim iniFile$, lnIni%  
    
  lnIni = FreeFile  
  iniFile$ = App.Path + "\copykoi8.ini"  
  On Error GoTo ErrFile  
  Open iniFile For Input As #lnIni  
    ' файл существует  
    Input #lnIni, PathFrom  
    Input #lnIni, PathTo  
  Close #lnIni  
  Exit Sub
ErrFile:  'нет файла, установка по умолчанию
  PathFrom = "d:\my-sites\visualmy\"  
  PathTo = "e:\dreamwear\visual\"  
End Sub

Запустите проект. Сейчас файла INI нет, поэтому должны произойти установки путей по умолчанию. Теперь создайте файл CopyKoi8.INI в каталоге с проектом и убедитесь, что используются его данные.

 

Кстати, как раз для тестирования можно создать файл с тестовым результирующим каталогом:

"d:\my-sites\visualmy\" 
"e:\tmp\"

Шаг 9. Создание Log-файла.

Создадим пока Log-файл с фиксированным именем CopyKoi8.log в каталоге, где находится утилита. Для сохранения файлов для разных сеансов работы утилиты их можно переименовать вручную.

В разделе Declaration опишем переменную:

Dim lnLog  ' логический номер Log-файла

В конце процедуры Form_Load запишем обращение к Call LogFileStart, а в процедуру Form_Unload — Call LogFileFinish. Затем — процедуры инициализации и закрытия Log-файла:

Public Sub LogFileStart()  
   ' инициализация Log-файла
   lnLog = FreeFile  
   Open App.Path + "\copykoi8.log" For Output As #lnLog  
   Print #lnLog, Me.Caption  
   Print #lnLog, lblFrom  
   Print #lnLog, lblTo  
   Print #lnLog, "Время начала: " & Date & " " & Time  
   Print #lnLog, "======="  
End Sub  
   
Public Sub LogFileFinish()  
   ' закрываем Log-файл
   ' статистика работы:
   Print #lnLog, "======="  
   Print #lnLog, lblCopy  
   Print #lnLog, lblConv  
   Print #lnLog, lblReplace  
   Print #lnLog, "Время начала: " & Date & " " & Time  
   Close #lnLog  
End Sub  

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

 

Запустите проект и сразу же закройте его. Убедитесь, что файл сформирован там, где нужно, и содержит информацию такого вида:

 

Преобразование из Win в KOI8

Откуда: d:\my-sites\visualmy\

Куда:  e:\tmp\

Время начала: 23.10.00 19:44:48

Скопировано файлов    = 0

Перекодировано файлов = 0

Заменено файлов = 0

Время начала: 23.10.00 19:44:50

 

Шаг 10. Формирование содержательной части Log-файла. Добавьте всего одну строку кода в процедуру cmdCopy_Click (перед комментарием «обновление счетчиков на форме»):

Print #lnLog, FileTo & sCopy & sReplace ' запись в Log-файл  

Запустите проект и скопируете несколько файлов. Убедитесь, что внутри Log-файла появилась информация об обработанных файлах:

e:\tmp\index.htm Скопирован (замена)
e:\tmp\kol.gif Скопирован (замена)
e:\tmp\email.htm Скопирован (новый)
e:\tmp\proffi.htm Скопирован (новый)

Мы завершили второй этап разработки. Созданный вариант утилиты можно передавать пользователям, которые будут довольны наличием протокола работы и возможностью изменения имен исходных каталогов. Распечать Log-файл они смогут с помощью NotePad — мы пока не будем отвлекаться от более актуальных задач.

В начало

В начало

Этап 3: перекодировка файлов

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

Сейчас наши процедуры сосредоточены в одном модуле формы, и поскольку их достаточно много, работать с ними не очень удобно. К тому же там есть одна процедура, функциональность которой будет возрастать и которая понадобится для работы в других режимах. Короче говоря, было бы полезно немедленно (дальше будет сложнее) отделить ее от конкретной формы и записать в отдельный модуль кода. Речь, конечно же, идет о процедуре cmdCopy_Click, где выполняются операции преобразования файла.

 

Шаг 11. Создадим в проекте новый модуль кода и назовем его CopyFile.BAS. Далее скопируем в него процедуру cmdCopy_Click и переименуем в CopyConvFile. Теперь нужно «склеить» эти процедуры, удалив из каждой из них ненужный код.

  1. Переместим из модуля frmCopy8.frm в CopyFile.bas все описания переменных в секции Declaration, заменим описания Dim на Public (то есть они будут общими переменными проекта).
  2. В процедуре CopyConvFile исправим заголовок:
Public Sub CopyConvFile(PathCur$, ByVal FileFrom$)  
  '
  ' Копирование и перекодирование файла
  ' PathCur  - имя текущего каталога
  ' FileFrom - имя файла (внутри текущего каталога)

Далее из этой процедуры нужно удалить код:

  FileFrom = filList.FileName 
  If FileFrom = "" Then 
    MsgBox "Не выбран файл!": Exit Sub
  End If

Затем двумя строчками ниже заменим в двух местах filList.Path на PathCur. В конце процедуры заменим:

Call CountCaption  

на:

Call frmCopy8.CountCaption  ' нужно указать объект, где находится процедура

Внимание! Переменная FileFrom будет меняться внутри процедуры, поэтому используем режим передачи параметра по значению (в вызывающей процедуре передаваемая переменная не будет меняться).

  1. В процедуре cmdCopy_Click нужно все удалить почти, оставив только следующий код:
Private Sub cmdCopy_Click()
  If filList.FileName = "" Then  
    MsgBox "Не выбран файл!": Exit Sub
  End If
  ' преобразование файла:
  Call CopyConvFile(filList.Path, filList.FileName)  
End Sub

Запустите проект и убедитесь, что все работает по-прежнему.

 

Шаг 12. Перекодировка файлов. Включите в процедуру CopyConvFile код для перезаписи текстовых файлов:

If FileExt$ = ".txt" Or FileExt$ = ".htm" Then  
    'перекодирование + копирование
    Dim WinLine$, Koi8Line$
    lnFrom = FreeFile: Open FileFrom For Input As #lnFrom  
    lnTo = FreeFile: Open FileTo For Output As #lnTo  
    While Not EOF(lnFrom)  
      Line Input #lnFrom, WinLine  
      Koi8Line = WinLine  
      Print #lnTo, Koi8Line  
    Wend
...

Очевидно, что пока этот код просто без перекодировки переписывает текстовый файл. И тем не менее...

 

Запустите проект и убедитесь, что теперь при указании HTM- или TXT-файлов производится изменение счетчика «Перекодировано», а в Log-файле появились записи  с комментарием «Перекодирован Win -> KOI8 (замена)». Проверьте, точно ли выполняется копирование текста.

 

Для перекодировки символов мы используем процедуру, о которой рассказывалось еще в нашем Совете 120. Подключим к нашему проекту созданный еще три года назад модуль Str_che.BAS (его можно скачать с http://www.visual.2000.ru/develop/vb/source/) и в приведенном выше коде вместо присвоения Koi8Line = WinLine запишем:

Koi8Line = RusSymOther$(WinLine, 3, 2) 'из Win/cp1251 в KOI-8

Запустите проект и убедитесь, что теперь HTM- или TXT-файлы при копировании перекодируются из кодировки Windows-1251 в KOI-8.

 

Шаг 13. Вполне вероятно, что будет полезен вариант, при котором возникнет необходимость копировать все файлы без перекодировки. Для этого нужно разместить на форме флажок с именем chkTxtHtm и установить для него в исходном положении свойство Value = 1 (Checked). Для использования этого флажка следует немного модифицировать код процедуры CopyConvFile:

Public Sub CopyConvFile(PathCur$, ByVal FileFrom$, CheckConv%)  
...
  ' CheckConv = 1 - перекодировать TXT/HML
  '           = 0 - не нужно
...
  If (CheckConv = 1) And (FileExt$ = ".txt" Or FileExt$ = ".htm") Then  
...
   
Обращение к ней из cmdCopy_Click будет выглядеть теперь следующим образом:
   
Call CopyConvFile(filList.Path, filList.FileName, chkTxtHtm.Value)  

Запустите проект и убедитесь, что он правильно работает с учетом положения флажка.

В начало

В начало

Заключение

Третья версия нашей утилиты реализована (рис. 2), и ее можно передать пользователям. Она позволяет решать два важных пункта (2-й и 3-й) нашей исходной задачи — копирование и перекодировку файлов. Эта операция теперь будет выполняться быстрее, а самое главное — надежнее:

  1. Файлы гарантированно копируются в нужное место (в соответствующий подкаталог).
  2. Обеспечена правильность перекодирования (раньше можно было забыть что-то перекодировать или, наоборот, забыть обработать какие-то файлы).
  3. Обеспечено получение точного протокола с измененными файлами, который затем переписывается на Web-сервер. Для контроля его можно сверить с исходным списком.

Следующий этап нашей работы — автоматическое получение исходного списка файлов, которые нужно обработать. Об этом — в следующей части статьи.

КомпьютерПресс 2'2001