скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Транслитератор названий mp3-файлов FileTranslator



Автор: Denny

С того момента, как подруга приобрела музыкальный центр, читающий диски mp3, мой десктоп стал резать музыкальные болванки в небывалых ранее количествах. Не сразу, но все же всплыл вопрос нормальной записи файлов, названных по-русски, так как центр отказывался читать названия по-русски, выдавая вместо связки "исполнитель-песня" какую-то чушь. Переименовывать "руками" сотню с лишним файлов - обезьянья работа, которую можно произвести однократно из любви к искусству, но не более. Возникло желание автоматизировать процесс, и я задумался как это можно сделать.

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

Средством решения поставленной задачи была выбрана программа, помещаемая в папку с mp3-файлами (для упрощения программы), предназначенными для копирования на CD, и переименовывающая все файлы, содержащие в названии буквы кириллицы. Все символы кириллицы заменяются на соответствующие им латинские по правилам транслитерации. Так как музыкальный центр читает только названия файлов, но не теги, то с ними морочиться я не счел нужным. Что получилось? Получилось, что программа не получает от пользователя никаких указаний (кроме запуска) и никаких сообщений пользователю не выдает. То есть нет необходимости в каком бы то ни было интерфейсе, что значительно упрощает поставленную задачу и уменьшает размер программы.

Распишем алгоритм работы программы. Он прост: перебор файлов в папке и проверка их названий на наличие русских букв, при положительном ответе - переименование. Все.

Что ж, приступим.

Для начала напишем процедуру переименования. У меня она получилась такой:

function Renaming(fn: TSearchRec): string;
// Функция переименования файла .mp3 транслитерацией
var
  S: string;
  i, j: Byte;
  Ch: Char;
begin
  S := extractfilename(fn.Name);
  j := Length(S);
  result := '';
  for i := 1 to j do
  begin
    Ch := S[i];
    case Ch of
      'А': result := result + 'A';
      'а': result := result + 'a';
      'Б': result := result + 'B';
      'б': result := result + 'b';
      'В': result := result + 'V';
      'в': result := result + 'v';
      'Г': result := result + 'G';
      'г': result := result + 'g';
      'Д': result := result + 'D';
      'д': result := result + 'd';
      'Е': result := result + 'E';
      'е': result := result + 'e';
      'Ё': result := result + 'Yo';
      'ё': result := result + 'yo';
      'Ж': result := result + 'Zh';
      'ж': result := result + 'zh';
      'З': result := result + 'Z';
      'з': result := result + 'z';
      'И': result := result + 'I';
      'и': result := result + 'i';
      'Й': result := result + 'I';
      'й': result := result + 'i';
      'К': result := result + 'K';
      'к': result := result + 'k';
      'Л': result := result + 'L';
      'л': result := result + 'l';
      'М': result := result + 'M';
      'м': result := result + 'm';
      'Н': result := result + 'N';
      'н': result := result + 'n';
      'О': result := result + 'O';
      'о': result := result + 'o';
      'П': result := result + 'P';
      'п': result := result + 'p';
      'Р': result := result + 'R';
      'р': result := result + 'r';
      'С': result := result + 'S';
      'с': result := result + 's';
      'Т': result := result + 'T';
      'т': result := result + 't';
      'У': result := result + 'U';
      'у': result := result + 'u';
      'Ф': result := result + 'F';
      'ф': result := result + 'f';
      'Х': result := result + 'H';
      'х': result := result + 'h';
      'Ц': result := result + 'Ts';
      'ц': result := result + 'ts';
      'Ч': result := result + 'Ch';
      'ч': result := result + 'ch';
      'Ш': result := result + 'Sh';
      'ш': result := result + 'sh';
      'Щ': result := result + 'Chsh';
      'щ': result := result + 'chsh';
      'Ъ': result := result + '''' + '''';
      'ъ': result := result + '''' + '''';
      'Ы': result := result + 'Y';
      'ы': result := result + 'y';
      'Ь': result := result + '''';
      'ь': result := result + '''';
      'Э': result := result + 'E';
      'э': result := result + 'e';
      'Ю': result := result + 'Yu';
      'ю': result := result + 'yu';
      'Я': result := result + 'Ya';
      'я': result := result + 'ya'
    else
      result := result + Ch
    end
  end;
  if FileExists(result) then
    result := '' // в случае существования файла с таким же именем
end;

В функцию передается информация о найденном файле. Здесь из него извлекается имя и посимвольно преображается. Результат преображения передается в вызывающую программу. Обратите внимание на последнюю операцию в функции. В ней происходит проверка на существование в папке файла с именем, совпадающим с результатом транслитерации имени другого файла, так как в случае попытки присвоения уже существующего имени происходит фатальная ошибка. Ведь равно возможны две ситуации : переименование файла Queen - Show Must Go On.mp3 в Queen - Show Must Go On.mp3, что глупо, и переименование Секрет - Алиса.mp3 в Sekret - Alisa.mp3 при существовании файла Sekret - Alisa.mp3 , что фатально. Сейчас же и отвечу, почему не переименовывается здесь же. Первоначально новое имя файл обретал здесь же, в функции переименования, но во время тестирования программы в папке с большим количеством файлов, начинался перебор уже переименованных файлов. То есть возникла необходимость разделения во времени процедур перебора и непосредственного переименования.

Обратимся теперь к главной программе:

var
  R: TextFile;
  Renamed: file;
  S, NewName: string;
  MusicFile: TSearchRec;
  i, b: Integer;
begin
  AssignFile(R, 'R.1'); // связываем файловую переменную с временным файлом R.1
  if FindFirst('*.mp3', faAnyFile, MusicFile) = 0 then
  begin
    Rewrite(R);
    b := 0;
    repeat
      NewName := Renaming(MusicFile);
      if NewName <> '' then
      begin
        inc(b); // считаем mp3-файлы
        WriteLn(R, NewName); // заносим новое название файла во временный файл
        WriteLn(R, MusicFile.Name) // заносим старое название файла туда же
      end
    until FindNext(MusicFile) <> 0;
    CloseFile(R);
    Reset(R);
    for i := 1 to b do
    begin
      ReadLn(R, NewName);
      ReadLn(R, S);
      AssignFile(Renamed, S);
      Rename(Renamed, NewName)
    end;
    CloseFile(R);
    Erase(R);
    FindClose(MusicFile)
  end
end.

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

Программа перебирает содержимое директории по маске '*.mp3', отбрасывая все "другие" файлы. Как только находится первый подходящий файл, создается временный файл R.1, а сам музыкальный файл "отправляется" на переименование. После перебора всех файлов директории временный файл закрывается и вновь открывается, уже для чтения. Согласно сделанным в нем записям производится переименование.

Анализ. Нельзя сказать, что приведенная реализация идеальна. Начнем с того, что если произвести извлечение имени файла в теле программы, и в функцию отправлять уже fn : String, то эту процедуру без значительных преобразований можно использовать в другой программе для транслитерации строк. Спорен также выбор файла для хранения временных данных. Можно для этих же целей воспользоваться динамическим массивом, но это увеличит требования программы к объему оперативной памяти (хотя современные компьютеры не страдают ее недостатком), зато вырастет скорость исполнения (человеку не ощутить разницу) из-за различий времени доступа к постоянной и оперативной памяти. Мало того, можно вообще отказаться от хранения временных данных. Ну и что с того, что программа будет переименовывать уже переименованные файлы? От присвоения файлу его же собственного имени мы себя застраховали, а увеличившееся время работы, повторяю, неощутимо и абсолютно не критично.

То есть, размер кода можно значительно сократить, сохранив при этом работоспособность программы, надо только преобразовать функцию Renaming в процедуру.

Тогда основная программа будет выглядеть так:

var
  MusicFile: TSearchRec;
begin
  if FindFirst('*.mp3', faAnyFile, MusicFile) = 0 then
  begin
    repeat
      Renaming(MusicFile)
    until FindNext(MusicFile) <> 0;
    FindClose(MusicFile)
  end
end.

Повторю, необходимо немного переделать функцию Renaming. Например так:

procedure Renaming(fn: TSearchRec);
var
  Renamed: file;
  OldName, NewName: string;
  i: Byte;
  Ch: Char;
begin
  OldName := ExtractFileName(fn.Name);
  for i := 1 to Length(OldName) do
  begin
    Ch := OldName[i];
    case Ch of
      'А': NewName := NewName + 'A';
      ...
        'я': NewName := NewName + 'ya'
    else
      NewName := NewName + Ch
    end;
    if not FileExists(NewName) then
    begin
      AssignFile(Renamed, OldName);
      Rename(Renamed, NewName)
    end
  end;

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






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook