Скажем, у нас есть имя файла в формате Filename.jpg в переменной FileName. Далее код на уровне идеи…
Вариант 1 через GUID
1 2 3 4 5 6 |
var newguid:tguid; ... //Генерируем уникальный guid Createguid(newguid); newUniqueName:=newguid.ToString; ... |
Вот пример такого изменения. Сохраняем часть старого имени для читабельности и добавляем GUID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
{Creating New Unique Name with a rest of old name, using GUID} function CreateUniqueNameAddingGUID(FileName: string; MaxOriginNameLength: Integer): string; var Extension:string; SplittedString: TArray<String>; SomeStringToChange: string; newguid:tguid; i: Integer; FileNameTemp:string; begin //Checks if FileName='' then Exit; //if MaxOriginNameLength=0 then exit; // if MaxOriginNameLength=0 will be only GUID as a result //1--------- First of all we need to extract extension if it is SplittedString:=FileName.Split(['.']); //we suppose that extensions are symbols after last '.', so... // if FileName has extension like 'SomeFileName.exe' if Length(SplittedString)>0 //1 and more, for example somename.ext [somename,ext] then begin Extension:=SplittedString[ High(SplittedString) ]; //Lets join everything except extension for i := Low(SplittedString) to High(SplittedString)-1 do begin if i=0 then SomeStringToChange:=SomeStringToChange+SplittedString[i] else SomeStringToChange:=SomeStringToChange+'.'+SplittedString[i]; end; //Cutting name up to the MaxOriginNameLength if Length( SomeStringToChange )> MaxOriginNameLength then SomeStringToChange:=SomeStringToChange.Substring(0,MaxOriginNameLength); //Adding GUID Createguid(newguid); SomeStringToChange:=SomeStringToChange+newguid.ToString; // Joining Extension SomeStringToChange:=SomeStringToChange+'.'+Extension; Result:=SomeStringToChange; end else // if FileName without Extension like 'SomeFileName' if Length(SplittedString)=0 then begin FileNameTemp:=FileName; //Cutting name up to the MaxOriginNameLength if Length( FileNameTemp )> MaxOriginNameLength then FileNameTemp:=FileNameTemp.Substring(0,MaxOriginNameLength); //Adding GUID Createguid(newguid); FileNameTemp:=FileNameTemp+newguid.ToString; Result:=FileNameTemp; end; //ShowMessage(Result); end; |
Вариант 2 через Random
Отделим имя от расширения, в предпоследнем элементе массива заменим имя на уникальное через Random
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
...var SplittedString: TArray<String>; newUniqueName:string; //--------------- Делим и заменяем предпоследний элемент массива на уникальный SplittedString:=FileName.Split(['.']); // Делим и загружаем в массив if High(SplittedString)>=1 then begin SplittedString[ High(SplittedString)-1 ]:= SplittedString[High(SplittedString)-1]+Random(10000000).ToString; end; //--------------Склеиваем обратно for i := Low(SplittedString) to High(SplittedString) do begin if i=High(SplittedString) then newUniqueName:=newUniqueName+SplittedString[i] else newUniqueName:=newUniqueName+SplittedString[i]+'.'; end; |
Алгоритм хорош, но есть вероятность совпадения имен. Как выход, можно гонять этот метод рекурсивно до исчезновения совпадений. Файлы будут вида
1 |
Filename98735618.jpg |
Мне этот алгоритм нравится, но не до конца… Он работает быстро, но сам вид файла, не эстетичен))
Вариант 3 через циклы while / repeat
В данном случае, через цикл while, но можно переписать и через repeat, алгоритм работает медленнее (O(n2)), чем предыдущий, но имена файлов получаются более красивыми
1 2 3 |
Filename(2); Filename(3); И так далее |
Пример из проекта… Есть список имен, с которым мы сравниваем
1 |
FilesOnServer:TStringList; // << где-то в проекте... |
Далее функция. Есть ли такой файл в списке? В данном случае на сервере?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function TVisualFrame_PSFTPClient.IsSuchFileOnServer(FileName:string):boolean; var i: Integer; SplittedString:TArray<String>; begin Result:=False; // Сравниваем в цикле for i:=0 to FilesOnServer.Count-1 do begin SplittedString:=FilesOnServer[i].Split(['.']); if (High(SplittedString)>=1) and ( Filename=SplittedString[ High(SplittedString)-1 ] ) then Result:=true; end; |
Далее функция создания уникального имени
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function TVisualFrame_PSFTPClient.CreateUniqueName(Filename: string): string; var n:integer; NewFileName:string; begin // FillFilesOnServer; n:=1; NewFileName:=Filename; while IsSuchFileOnServer(NewFileName) do begin NewFileName:=NewFileName+'('+n.ToString+')'; n:=n+1; end; Result:=NewFileName; end; |
И последнее – проверка и создание уникального имени в случае необходимости
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var SplittedString:TArray<string>; i:integer ... if FilesOnServer.IndexOf( tempstring )<>-1 then begin //Делим... SplittedString:=FileName.Split(['.']); //Заменяем... SplittedString[ High(SplittedString)-1 ]:= CreateUniqueName(SplittedString[ High(SplittedString)-1 ]); //Вставляем обратно for i := Low(SplittedString) to High(SplittedString) do begin if i=High(SplittedString) then NewNameOnServer:=NewNameOnServer+SplittedString[i] else NewNameOnServer:=NewNameOnServer+SplittedString[i]+'.'; end; end; .. |