Консультация № 161434
26.02.2009, 01:58
0.00 руб.
0 1 0
Здравствуйте.
Пишу простейшую программу – клиент FTP (Delphi2009/idFTP). Столкнулся со сложностью – не могу понять как передать файл с русскими символами в названии. В разных случаях происходит по-разному: – либо программа вылетает с ошибкой (не могу создать файл ??????? ????? ?????? [вопросы вместо русского названия]), - либо файл заливается на сервер, но имя у файла меняется на вопросы. Пробовал разные кодировки – вместо вопросов получил крякозябры =)
Небезызвестный FTP менеджер FileZilla на требуемый сервер спокойно заливает файлы с русскими именами. Подскажите, пожалуйста, как можно решить эту проблему.

Пример специально упростил, делаю так:
Код:

procedure TForm1.Button1Click(Sender: TObject);
var
FileName : String;
FileStream: TFileStream;
St: String;
begin
with IdFTP1 do begin
Host := '192.168.145.55'; // host
Username := 'user'; // username
Password := 'pwd'; // password

Connect; // make a connection

FileName:=('d:\безымянный.bmp'); // файл с русскими буквами в названии

FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);

try
try
TransferType := ftBinary; // or ftASCII IdFTPCommon.pas
//Start transfering packed files

St := ExtractFileName(FileName);
//тут, вероятно, необходимо сменить кодировку.

Put(FileStream, St);

Quit; // close the connection
except
On E: Exception do ShowMessage(E.Message);
end;
finally
FileStream.Free;
end;
end;{with}


end;

Обсуждение

Неизвестный
28.02.2009, 04:12
общий
Нашёл решение благодаря разным форумам и небесам =).

Может быть оно не совсем грамотное, но работает.

По умолчанию в инди установлена кодировка en7bit, более того, она вшита железно (idFTP.pas):

Код:
function TIdTCPConnection.SendCmd(AOut: string; const AResponse: SmallInt = -1;
const AEncoding: TIdEncoding = en7bit): SmallInt;
begin
if AResponse < 0 then begin
Result := SendCmd(AOut, [], AEncoding);
end else begin
Result := SendCmd(AOut, [AResponse], AEncoding);
end;
end;


Т.к. все команды FTP передаются сюда, то по умолчанию используется эта кодировка. Более того, для работы с интернациональными символами используется преобразование в кодовую страницу 1252.

Вообще, существует некий TIdIOHandler.DefStringEncoding где по идее можно выставить требуемую кодировку, а потом присвоить например в idFTP.IOHandler этот IdIOHandler. Но, к сожалению из этого (лично у меня) ничего не получилось.

Выход получается такой.
Нужно сначала написать ф-ии для преобразования кодовых страниц 1251-1252 и обратно. А вот далее, придётся править сам idFTP.pas.

У меня получилось сделать это так:


Код:
function FixStringGet(const AData: String): String;
type
TW1252 = type AnsiString(1252);
var
W1252: TW1252;
S: RawByteString;
begin
W1252 := AData; // В этой строке выполняются действия, которые раньше выполнял у меня цикл - это обратные действия к тем, что выполняет Indy
// Теперь копирование данных одним блоком в буфер
SetLength(S, Length(W1252));
Move(Pointer(W1252)^, Pointer(S)^, Length(W1252));
// Помечаем, что данные на самом деле имеют кодировку 1251
SetCodePage(S, 1251, False);
// Ну и конвертация в Unicode
Result := S;
end;

function FixStringPut(const AData: String): String;
type
TW1251 = type AnsiString(1251);
var
W1251: TW1251;
S: RawByteString;
begin
W1251 := AData; // В этой строке выполняются действия, которые раньше выполнял у меня цикл - это обратные действия к тем, что выполняет Indy
// Теперь копирование данных одним блоком в буфер
SetLength(S, Length(W1251));
Move(Pointer(W1251)^, Pointer(S)^, Length(W1251));
// Помечаем, что данные на самом деле имеют кодировку 1251
SetCodePage(S, 1252, False);
// Ну и конвертация в Unicode
Result := S;
end;


А в самом idFTP.pas, необходимо заменить ВСЕ вызовы SendCmd(). На примере RNFR это выглядит так:


Код:

//Заменить с
SendCmd( 'RNFR ' + '1.txt', 350);
// Заменить на:
SendCmd( 'RNFR ' + '1.txt', 350, enUtf8);


Конечно, можно попытаться унаследовать всё от idFTP и TIdTCPConnection в новый класс, где уже не будет en7bit, но мне кажется более простым метод именно непосредственного изменения idFTP.pas. По крайней мере для моих задач этого вполне достаточно. Всем спасибо за внимание, проблема решена.
Форма ответа