Страница Ивана Рощина > Статьи >

© Иван Рощин, Москва

ZXNet: 500:95/462.53
E-mail: bestview@mtu-net.ru
WWW: http://www.ivr.da.ru

Добавление в HTML-документы информации об их кодировке

Радиомир. Ваш компьютер» 10/2003)

Введение
Определение кодировки
Текст программы
Как она работает?
Руководство пользователя
Создание списка файлов
Литература

Введение

По разным причинам не во всех HTML-документах присутствует атрибут «charset», указывающий их кодировку. При работе в Интернете это может не иметь значения, если браузер получает сведения о кодировке непосредственно от сервера, передающего документ. Но если записать такой документ на диск и затем открыть его для просмотра, то пользователю придётся самому указывать кодировку, так как браузеру больше неоткуда будет её узнать (если только браузер не умеет автоматически определять кодировку, анализируя содержимое документа).

Столкнувшись с этой проблемой, я решил написать программу, которая анализировала бы сохранённые пользователем на диске HTML-документы и при отсутствии в каком-либо документе атрибута «charset» автоматически определяла бы кодировку этого документа и добавляла бы в него информацию о кодировке.

Определение кодировки

Все имеющиеся у меня HTML-документы были либо в кодировке Windows-1251 (далее WIN), либо в KOI8-R (далее KOI). Видимо, документы в других кодировках встречаются в русскоязычной части Интернета очень редко. Таким образом, программа должна уметь определять, какая из этих двух кодировок соответствует обрабатываемому документу.

В своих статьях [1] и [2] я уже рассматривал различные алгоритмы автоматического определения кодировки текста. В [1] был рассмотрен алгоритм выбора между кодировками ALT и WIN, основанный на особенности этих кодировок и неодинаковой частоте встречаемости различных букв, а в [2] — модификация этого алгоритма для кодировок WIN и KOI, а также другой алгоритм для выбора между кодировками ALT, WIN и KOI, основанный на том, что не все возможные сочетания букв могут встречаться в словах. Но при написании рассматриваемой программы я решил использовать ещё один алгоритм, совершенно отличный от предыдущих и основанный на одной особенности кодировок WIN и KOI.

Табл. 1. Кодировка WIN
0 1 2 3 4 5 6 7 8 9 A B C D E F
C А Б В Г Д Е Ж З И Й К Л М Н О П
D Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я
E а б в г д е ж з и й к л м н о п
F р с т у ф х ц ч ш щ ъ ы ь э ю я
Табл. 2. Кодировка KOI
0 1 2 3 4 5 6 7 8 9 A B C D E F
C ю а б ц д е ф г х и й к л м н о
D п я р с т у ж в ь ы з ш э щ ч ъ
E Ю А Б Ц Д Е Ф Г Х И Й К Л М Н О
F П Я Р С Т У Ж В Ь Ы З Ш Э Щ Ч Ъ

Коды прописных букв в кодировке WIN являются кодами строчных букв в кодировке KOI, и наоборот (табл. 1, 2). То есть при неправильном определении кодировки прописные буквы станут строчными, а строчные — прописными.

В обычном тексте (рис. 1 а) строчная буква может встретиться после прописной (например, в начале предложения), а прописная после строчной — не может. Если же в результате неправильного определения кодировки (рис. 1 бв) прописные буквы стали строчными, а строчные — прописными, то в тексте можно будет встретить прописную букву после строчной, и нельзя — строчную после прописной.

a) кодировка определена правильно

б) WIN распознана как KOI

в) KOI распознана как WIN

Рис. 1

Таким образом, алгоритм определения кодировки оказывается очень простым. Просматриваем текст, пока не обнаружим два соседних символа, код одного из которых принадлежит диапазону C0h—DFh, а код другого — диапазону E0h—FFh. (То есть один из этих символов — прописная буква, а другой — строчная.) Если код первого символа принадлежит диапазону C0h—DFh, то кодировка текста — WIN, иначе — KOI. (Так как первый символ должен быть прописной буквой, а второй — строчной.)

Если весь текст просмотрен, но требуемых двух символов не обнаружено, алгоритм не может определить кодировку текста.

Этот алгоритм, в отличие от описанных в [1] и [2], может определить кодировку текста по единственному слову из строчных букв, начинающемуся с прописной буквы, и не требует набора статистики — а значит, определение кодировки будет более быстрым и точным. Но он годится только для выбора между WIN и KOI.

Текст программы

/* +-----------------------------------------------------------------------+ */
/* | CharSET 1.0 - добавление в HTML-документы информации об их кодировке. | */
/* | (c) Иван Рощин, Москва, 2003.                                         | */
/* | E-mail: bestview@mtu-net.ru                 WWW: http://www.ivr.da.ru | */
/* +-----------------------------------------------------------------------+ */

/* Компилятор: Turbo C 2.0. */

#include <io.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <dir.h>
#include <dos.h>

/* ========================== Описание функций =========================== */

int get_line (FILE* f, char* fullname);
void proc_file (char *filename);
int cmp_str (FILE* f, char* s);
int find_charset (FILE* f, fpos_t* pos);
int def_winkoi (FILE* f);
int set_dir (char *s, char *name);
FILE* fopen_1 (char* name, char* mode);
int fgetc_1 (FILE* f);
void fputc_1 (int c, FILE* f);
void fputs_1 (char* s, FILE* f);
void set_dir_1 (char *s, char *name);
void fclose_1 (FILE* f);

/* ======================== Пошла сама программа ========================= */

int main (int argc, char *argv[])
{
 FILE *f_list;
 char s[129];

 printf ("\n+-----------------------------------------------------------------------+\n");
 printf   ("| CharSET 1.0 - добавление в HTML-документы информации об их кодировке. |\n");
 printf   ("| (c) Иван Рощин, Москва, 2003.                                         |\n");
 printf   ("| E-mail: bestview@mtu-net.ru                 WWW: http://www.ivr.da.ru |\n");
 printf   ("+-----------------------------------------------------------------------+\n");

 if (argc<2) {printf ("\nSyntax: charset.exe HTML-file or @list-of-HTML-files\n\n"); exit(1);}

 if (argv[1][0]!='@') proc_file (argv[1]); /* Обработка одного файла. */
 else
 { /* Открываем файл со списком файлов.
      Если указан полный путь - переходим в нужный каталог. */
  if ((strlen(argv[1]+1)>=3)&&(argv[1][2]==':'))
  {
   set_dir_1(argv[1]+1,s);
   f_list=fopen_1(s,"rb");
  }
  else f_list=fopen_1(argv[1]+1,"rb");
  /* Обработка файлов из списка. */
  while (get_line(f_list,s)==1) proc_file(s);
  fclose_1 (f_list);
 }
 printf ("\n\n"); exit (0);
}

/* ==========================================================================
   Функция get_line - чтение строки из файла.
   Выход: при удачном завершении в fullname - прочитанная строка, и функция
   возвращает 1. Если файл кончился или встретилась пустая строка -
   возвращает 0. Если длина строки больше 128 символов - выполнение программы
   прерывается.
 ========================================================================= */

int get_line (FILE* f, char* fullname)
{
 int i=0;
 int c;

 c=fgetc_1(f);
 if ((c==EOF)||(c==13)) return (0); /* Конец файла или пустая строка. */
m1:
 fullname[i]=c; fullname[i+1]=0;    /* Добавили символ в строку. */
 c=fgetc_1(f); if (c==EOF) return (1);                /* Конец файла.  */
 if (c==13) {c=fgetc_1(f); /* skip 10 */ return (1);} /* Конец строки. */
 i++; if (i<=128) goto m1;
 printf ("\nСтрока длиннее 128 символов в списке файлов!\n\n"); exit (1);
}

/* ==========================================================================
   Функция proc_file - обработка файла с указанным именем (и, возможно, путём
   к этому файлу).
 ========================================================================= */

void proc_file (char *fullname)
{
 FILE *f_src, *f_dst;
 int c,a;
 fpos_t pos;
 int charset;
 char command[255];
 char filename[13];
 unsigned long i;
 char* win="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1251\">";
 char* koi="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=KOI8-R\">";

 /* Печатаем переданное функции имя файла. */

 printf ("\n%s  ",fullname);

 /* Если указан полный путь - переходим в нужный каталог.
    Помещаем имя файла в filename. */

 if ((strlen(fullname)>=3)&&(fullname[1]==':')) set_dir_1(fullname,filename);
 else {for (i=0;i<12;i++) filename[i]=fullname[i]; filename[12]=0;}
 f_src=fopen_1(filename,"rb");

 /* Анализируем содержимое файла. */

 a=find_charset(f_src,&pos);
 if (a==1) {printf ("кодировка уже указана."); fclose_1 (f_src); return;}
 if (a==2) {printf ("некорректный формат файла."); fclose_1 (f_src); return;}

 /* Определяем кодировку. */

 printf ("кодировка");
 charset=def_winkoi(f_src);
 if (charset==0) {printf (" не распознана."); fclose_1 (f_src); return;}
 if (charset==1) printf (": windows-1251.");
 if (charset==2) printf (": KOI8-R.");

 /* Копируем исходный файл во временный файл: */

 strcpy (command,"copy /b ");
 strcat (command,filename);
 strcat (command," $$$$$$$$.tmp >nul");
 system (command);

 /* Открываем временный файл для чтения, исходный файл - для записи.
    Если при копировании обрабатываемого файла во временный файл не хватило
    места на диске, то временный файл не будет создан, и при попытке его
    открытия выполнение программы будет прервано. */

 fclose_1(f_src);
 f_src=fopen_1("$$$$$$$$.tmp","rb");
 f_dst=fopen_1(filename,"wb");

 /* Копируем pos байтов, записываем строку с указанием charset, а затем
    копируем остаток файла. */

 for (i=0;i<pos;i++) fputc_1(fgetc_1(f_src),f_dst);
 if (charset==1) {for (i=0;i<strlen(win);i++) fputc_1(win[i],f_dst);}
 else {for (i=0;i<strlen(koi);i++) fputc_1(koi[i],f_dst);}
 while ((c=fgetc_1(f_src))!=EOF) fputc_1(c,f_dst);

 /* Закрываем временный и исходный файлы, удаляем временный файл. */

 fclose_1 (f_src); fclose_1 (f_dst); remove ("$$$$$$$$.tmp");
}

/* ==========================================================================
   Функция find_charset - анализ файла f.
   Выход: 0 - charset не указан (и в файле имеется тег <head>, или нет <head>,
   но есть <body>). Тогда в переменной pos - смещение, с которого будем
   указывать charset (если в файле есть <head>, то pos указывает на позицию
   сразу после <head>; если в файле нет <head>, но есть <body>, то pos
   указывает на позицию сразу перед <body>.
          1 - charset указан.
          2 - charset не указан, и файл не содержит тегов <head> и <body>.
 ========================================================================= */

int find_charset (FILE* f, fpos_t* pos)
{
m1:
 if (cmp_str(f,"charset=")==1) return (1);
 if (cmp_str(f,"<head>")==1) {fgetpos (f,pos); *pos=*pos+6; goto m2;}
 if (cmp_str(f,"<body")==1) {fgetpos (f,pos); return (0);}
 if (fgetc_1(f)!=EOF) goto m1;
 return (2);

/* <head> обнаружен. Ищем, что попадётся первым: charset или </head>. */

m2:
 if (cmp_str(f,"charset=")==1) return (1);
 if (cmp_str(f,"</head>")==1) return (0);
 if (fgetc_1(f)!=EOF) goto m2;
 return (0);
}

/* ==========================================================================
   Функция cmp_str - проверяет совпадение (регистр букв не учитывается)
   заданной строки s и того, что находится в файле f с текущей позиции.
   Выход: 1 - совпадение, 0 - несовпадение. Позиция в файле не меняется.
 ========================================================================= */

int cmp_str (FILE* f, char* s)
{
 fpos_t pos;
 int c,i;
 static int t;
 unsigned long l;
 char prc[5];
 union REGS r1;

 fgetpos (f,&pos); /* Запомнили текущую позицию файла. */

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

 t++;
 if ((t&0x7ff)==0)
 {
  l=filelength(fileno(f))/100; /* l=1%              */
  if (l!=0) l=pos/l;           /* l=0..100          */
  sprintf (prc,"%ld%%",l);     /* prc="0%".."100%". */

  /* Выводим символы из строки prc на экран с помощью функций BIOS. Потом
     столько же раз отступаем назад, чтобы курсор вернулся на прежнее место. */

  r1.h.ah=0xf; int86 (0x10,&r1,&r1);
  i=0;
  do {r1.h.ah=0xe; r1.h.al=prc[i]; int86 (0x10,&r1,&r1); i++;}
  while (prc[i]!=0);
  r1.h.ah=0xe; r1.h.al=' '; int86 (0x10,&r1,&r1); i++;
  r1.h.ah=0xe; r1.h.al=' '; int86 (0x10,&r1,&r1); i++;
  do {r1.h.ah=0xe; r1.h.al='\b'; int86 (0x10,&r1,&r1); i--;}
  while (i>0);
 }

 /* Проверка совпадения строки s и содержимого файла. */

 for (i=0;i<strlen(s);i++)
 {
  if (tolower(fgetc_1(f))!=s[i]) {fsetpos (f,&pos); return (0);}
 }
 fsetpos (f,&pos);
 return (1);
}

/* ==========================================================================
   Функция def_winkoi - определение кодировки (WIN или KOI) указанного файла.
   Выход: 0 - кодировку не удалось определить, 1 - WIN, 2 - KOI.
 ========================================================================= */

int def_winkoi (FILE* f)
{
 int c1,c2;

 rewind(f); /* Позиционирование на начало файла. */
 c1=fgetc_1(f); if (c1==EOF) return (0);
m1:
 c2=fgetc_1(f); if (c2==EOF) return (0);
 if (((c1>=0xc0)&&(c1<=0xdf))&&((c2>=0xe0)&&(c2<=0xff))) return (1);
 if (((c2>=0xc0)&&(c2<=0xdf))&&((c1>=0xe0)&&(c1<=0xff))) return (2);
 c1=c2;
 goto m1;
}

/* ==========================================================================
   Функция set_dir.
   Вход: строка s с полным путём к файлу и именем файла (например,
   "c:\work\n.txt").
   Выход: каталог, в котором находится файл, установлен текущим; имя файла
   помещено в строку name; возвращается код завершения: 0 - OK, 1 - ошибка.
 ========================================================================= */

int set_dir (char *s, char *name)
{
 int a,d,i;
 char path[128];

 /* Разбиваем строку s на путь к файлу (path) и имя файла (name). */
 a=strlen(s)-1; /* Индекс последнего символа строки. */
 /* Просматриваем строку от конца к началу, пока не найдём символ '\',
    отделяющий путь к файлу от имени файла. */
 while (s[a]!='\\')
 {
  if (a==0) return (1); /* Символ '\' не найден - ошибка! */
  a--;
 }
 /* Копируем путь к файлу (не включая последний '\') в строку path. */
 for (i=0; i<a; i++) path[i]=s[i];
 path[i]=0;
 /* Копируем имя файла в строку name. */
 for (i=a+1; i<strlen(s); i++)
 {
  if ((i-a-1)==12) return (1); /* Имя больше 12 символов. */
  name[i-a-1]=s[i];
 }
 name[i-a-1]=0;
 /* Выбор диска. */
 if ((path[0]>='A')&&(path[0]<='Z')) d=path[0]-'A';
 if ((path[0]>='a')&&(path[0]<='z')) d=path[0]-'a';
 a=setdisk(d); if (d>=a) return (1); /* Выбран несуществующий диск. */
 /* Переходим в нужный каталог. */
 a=chdir(path); if (a!=0) return (1);
 return (0);
}

/* ==========================================================================
   Аналоги функций для работы с файлами (fgetc, fputc, fputs, fopen, set_dir,
   fclose). При ошибке прерывают выполнение программы; таким образом, после
   вызова этих функций не надо проверять, была ли ошибка.
 ========================================================================= */

int fgetc_1 (FILE* f)
{
 int c;
 c=fgetc(f); if ferror(f) {printf ("\nОшибка чтения!\n\n"); exit (1);}
 return (c);
}

void fputc_1 (int c, FILE* f)
{
 if (fputc(c,f)==EOF) {printf ("\nОшибка записи!\n\n"); exit (1);}
}

void fputs_1 (char* s, FILE* f)
{
 if (fputs(s,f)==EOF) {printf ("\nОшибка записи!\n\n"); exit (1);}
}

FILE* fopen_1 (char* name, char* mode)
{
 FILE* f;
 char* s;
 char* s1="чтение";
 char* s2="запись";

 f=fopen(name,mode);
 if (f==NULL)
 {
  if (mode[0]=='r') s=s1; else s=s2;
  printf ("\nОшибка открытия файла \"%s\" на %s!\n\n",name,s);
  exit (1);
 }
 return (f);
}

void set_dir_1 (char *s, char *name)
{
 if (set_dir(s,name)==1) {printf ("\nОшибка в пути к файлу или в имени файла!\n\n"); exit (1);}
}

void fclose_1 (FILE* f)
{
 if (fclose(f)==EOF) {printf ("\nОшибка закрытия файла!\n\n"); exit (1);}
}
Скачать исполняемый файл программы (для DOS) (9 КБ ZIP)
Скачать листинг программы в текстовом виде (4 КБ ZIP)

Как она работает?

Здесь я кратко расскажу, как программа обрабатывает HTML-документ (HTML-файл).

Ниже приведены необходимые сведения о структуре HTML-документа. Показаны только те элементы структуры, которые имеют значение при обработке документа; остальные элементы (некоторые из них могут отсутствовать в конкретном документе) обозначены как {…}.

Структура HTML-документа

Сначала программа просматривает файл, пока не встретит одну из следующих строк: «charset=», «<head>» или «<body». В процессе поиска информация о том, сколько процентов файла уже просмотрено, отображается на экране. Поиск производится без учёта регистра символов, так как теги «head» и «body» могут быть записаны как прописными, так и строчными буквами.

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

1. Если найдена строка «charset=», то программа считает, что кодировка в этом файле уже указана. Программа выводит соответствующее сообщение, и на этом обработка файла заканчивается.

2. Если найдена строка «<head>», то текущая позиция в файле запоминается (так как именно после тега «head» будет при необходимости добавлена информация о кодировке), и программа начинает поиск (с текущей позиции) одной из двух строк: «charset=» или «</head>». Если первой попадётся строка «charset=» — значит, кодировка в этом файле уже указана. Если же первой попадётся строка «</head>», или файл кончится до того, как попадётся какая-то из искомых строк, то программа посчитает, что кодировка в этом файле не указана, и перейдёт к определению кодировки.

3. Если найдена строка «<body», то текущая позиция в файле запоминается (так как именно перед тегом «body» будет при необходимости добавлена информация о кодировке), и программа переходит к определению кодировки.

4. Если ни одна из трёх строк не найдена, программа делает вывод, что файл не является корректным HTML-документом. Тогда программа выводит сообщение «некорректный формат файла», и на этом обработка файла заканчивается.

Определение кодировки происходит по алгоритму, рассмотренному в начале этой статьи. Полученный результат («windows-1251», «KOI8-R» или «не распознана») печатается на экране.

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

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<meta http-equiv="Content-Type" content="text/html; charset=KOI8-R">

Вставка строки производится следующим образом: сначала обрабатываемый файл копируется во временный файл «$$$$$$$$.tmp», находящийся в том же каталоге, затем временный файл открывается для чтения, а обрабатываемый файл — для записи. В обрабатываемый файл копируется часть временного файла от начала до позиции, с которой будет добавлена строка, затем записывается добавляемая строка и копируется остаток файла. После этого временный файл удаляется.

Руководство пользователя

В командной строке необходимо указать либо имя одного обрабатываемого HTML-файла, либо символ «@» и сразу за ним — имя текстового файла-списка, где содержатся имена обрабатываемых HTML-файлов. Если указываемый в командной строке файл находится в текущем каталоге, то путь к нему можно не указывать. В противном случае должен быть указан полный путь к файлу.

Ниже приведены несколько примеров:

charset.exe C:\WORK\doc.htm
charset.exe doc.htm
charset.exe @C:\WORK\list.txt
charset.exe @list.txt

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

Длина каждой строки в списке не должна превышать 128 символов, код конца строки должен быть (13,10), в последней строке списка код конца строки может отсутствовать.

На каждом из дисков, где находятся обрабатываемые файлы, свободного места должно быть не меньше, чем занимает самый длинный из обрабатываемых файлов, находящихся на этом диске. Дело в том, что, как уже упоминалось выше, при обработке файла программа создаёт в том же каталоге временный файл такой же длины, как и обрабатываемый. Также надо учесть, что размер обрабатываемых файлов возрастёт за счёт добавления информации о кодировке: длина каждого файла может увеличиться на 74 или 68 байтов.

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

В процессе работы программа выводит информацию о результате обработки каждого файла. Выглядит это примерно так:

C:\WORK\test_1.htm  кодировка: KOI8-R.
C:\WORK\test_2.htm  кодировка: windows-1251.
C:\WORK\test_3.htm  кодировка не распознана.
C:\WORK\test_4.htm  кодировка уже указана.
C:\WORK\test_5.htm  некорректный формат файла.
C:\WORK\test_6.htm  54%

Если обрабатывается много файлов, и вам надо знать, каковы результаты обработки каждого файла (а на экране вся информация не умещается), можно использовать перенаправление вывода в текстовый файл. Например, если вы хотите перенаправить вывод программы в файл n.txt, надо просто добавить в конце командной строки « > n.txt» (без кавычек).

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

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

Если появилось сообщение об ошибке открытия на чтение одного из обрабатываемых файлов — возможно, этот файл отсутствует, или в списке почему-то оказалось длинное имя файла (например, если при создании списка в Dos Navigator’e вы забыли выключить параметр «Использовать длинные имена файлов»).

Если появилось сообщение об ошибке открытия на запись одного из обрабатываемых файлов, это может говорить либо о том, что соответствующий диск защищён от записи (соответственно, защиту надо снять), либо о том, что для этого файла установлен атрибут «Read only» («только чтение»). Тогда надо снять этот атрибут. Если в том же каталоге есть и другие подлежащие обработке файлы, лучше проверить и их — вдруг у них тоже установлен атрибут «Read only»? Для изменения атрибутов файла или группы помеченных файлов в Dos Navigator’е служит комбинация клавиш Alt-F.

Если при обработке HTML-файла появилось сообщение «Ошибка открытия файла “$$$$$$$$.tmp” на чтение» — скорее всего, на диске, где находится обрабатываемый файл, не хватило места для создания временного файла «$$$$$$$$.tmp», поэтому программа и не может его открыть. Попробуйте увеличить количество свободного места на диске и повторно запустить программу.

Если появилось сообщение об ошибке записи в обрабатываемый файл или об ошибке при закрытии этого файла — возможно, на диске не хватило места, чтобы поместился обработанный файл, и записать его не удалось. Но не беспокойтесь, первоначальное содержимое этого файла не пропадёт, так как программа сначала копирует его во временный файл «$$$$$$$$.tmp», находящийся в том же каталоге. Таким образом, для восстановления исходного файла надо удалить исходный файл, а потом присвоить его имя временному файлу.

Если программа обрабатывала длинный список файлов, и ошибка возникла при обработке какого-то файла из середины списка, то после устранения причин ошибки не обязательно для продолжения обработки файлов удалять из списка имена уже обработанных файлов. Можно запустить программу, не изменяя список, при этом для уже обработанных файлов программа просто обнаружит, что в них уже присутствует атрибут «charset», и не изменит их.

Создание списка файлов

Для создания списка обрабатываемых HTML-файлов можно использовать команду DIR, перенаправив её вывод в файл (но эта команда должна быть выполнена не в Windows, а в чистом DOS, иначе в полученном списке окажутся длинные имена файлов, а описываемая в этой статье программа не работает с длинными именами).

Например, если надо получить в файле C:\list.txt список всех файлов с расширением htm, находящихся в каталоге C:\WORK и его подкаталогах, то вводим такую команду:

dir c:\work\*.htm /s /b >c:\list.txt

Более удобный способ создания списка — с помощью DOS Navigator’а (я использую DN OSP 2.7.0 — www.dnosp.ru). Помечаем нужные файлы, нажимаем Alt-W, появляется окно «Создать список файлов». В этом окне должен быть включён параметр «Сохранять полные пути файлов в списке» и выключен параметр «Использовать длинные имена файлов». Указываем имя файла-списка, нажимаем Enter и получаем требуемый результат.

Если надо получить список всех файлов, удовлетворяющих определённым условиям, то сначала используем функцию «Поиск файлов». Пусть, например, надо получить список всех файлов с расширениями htm, html и shtml, находящихся в каталоге C:\TEST и его подкаталогах. Заходим в каталог C:\TEST и нажимаем Alt-F7 («Поиск файлов»). Проверяем, чтобы была включена опция «Рекурсивный поиск» (чтобы поиск производился и в подкаталогах). В качестве области поиска выбираем «Текущий каталог». В строке «Маска файла» указываем «*.htm;*.html;*.shtml» (без кавычек). После окончания поиска помечаем найденные файлы (если ни один файл не помечен, то наиболее быстрый способ пометки всех файлов в панели — нажать «*» на цифровой клавиатуре) и нажимаем Alt-W, чтобы перейти к созданию списка помеченных файлов.

Литература

  1. И.Рощин. «Автоматическое определение кодировки текста». «Радиомир. Ваш компьютер» 10/2001.
  2. И.Рощин. «Автоматическое определение кодировки текста — 2». «Радиомир. Ваш компьютер» 5, 6/2002, 6/2004.

Другие мои статьи о создании и/или обработке HTML-документов:

1. 

«Преобразование псевдографических таблиц в формат HTML». «Радиомир. Ваш компьютер» 5—7/2003.

2. 

«Автоматическое проставление размеров файлов в HTML-документах». «Радиомир. Ваш компьютер» 11/2004.

Страница Ивана Рощина > Статьи >