Кодировкой текста Indy по умолчанию является ASCII (поскольку большинство интернет-протоколов по-прежнему в значительной степени основаны на ASCII, если только они не определяют дополнительные расширения для поддержки Unicode). Вот почему вы получаете ?
для символов, отличных от ASCII. Чтобы отправить символы, отличные от ASCII, вам нужно сообщить Indy, какую текстовую кодировку использовать, которая совместима с символами, которыми вы обмениваетесь. UTF-8 обычно является лучшим выбором для этого. Это можно сделать тремя способами:
установите глобальную переменную GIdDefaultTextEncoding
в блоке IdGlobal
. По умолчанию он установлен на encASCII
, вместо этого вы можете установить его на encUTF8
:
procedure TForm1.FormCreate(Sender: TObject);
begin
GIdDefaultTextEncoding := encUTF8;
end;
установите для свойства TIdIOHandler.DefStringEncoding
значение TIdTextEncoding.UTF8
(или IndyTextEncoding_UTF8
, если вы используете Indy 10.6+):
procedure TForm1.IdTCPClient1Connected(Sender: TObject);
begin
IdTCPClient1.IOHandler.DefStringEncoding := TIdTextEncoding.UTF8;
// or:
// IdTCPClient1.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
end;
передать TIdTextEncoding.UTF8
(или IndyTextEncoding_UTF8
) непосредственно в параметр AByteEncoding
WriteLn()
:
IdTCPClient1.IOHandler.WriteLn(..., TIdTextEncoding.UTF8);
// or:
// IdTCPClient1.IOHandler.WriteLn(..., IndyTextEncoding_UTF8);
Имейте в виду, что вы используете Ansi-версию Delphi, где string
сопоставляется с AnsiString
, и, таким образом, Indy должен выполнить дополнительное преобразование данных AnsiString из Ansi в Unicode, прежде чем он сможет затем применить указанную текстовую кодировку для получения байтов. передает. Как правило, Indy использует кодировку Ansi по умолчанию ОС для обработки этого начального преобразования (поэтому, если ваши данные AnsiString
закодированы в греческом языке, а ваша ОС настроена на греческий, все будет в порядке), однако вы можете использовать свойство TIdIOHandler.DefAnsiEncoding
или параметр ASrcEncoding
из WriteLn()
, если вам нужно указать, что ваши данные AnsiString
используют другую кодировку.
Что касается вашей ошибки сокета, не видя стека вызовов, ведущего к ошибке, или, по крайней мере, какая строка вашего кода ее вызывает, это трудно устранить. Я предполагаю, что это связано с тем, что вы вызываете ReadLn()
внутри блока finally
независимо от того, действительно ли удалось выполнить WriteLn()
или Write()
. Этот код нужно вынести из блока finally
, ему там не место.
Вместо этого попробуйте что-то вроде этого:
procedure TForm1.LoadFileButtonClick(Sender: TObject);
begin
OpenDialog1.Filter := 'All Files (*.*)';
OpenDialog1.FilterIndex := 1;
if OpenDialog1.Execute then
begin
Edit1.Text := ExtractFileName(OpenDialog1.FileName);
Edit3.Text := OpenDialog1.FileName;
// Indy has its own FileSizeByName() function...
Edit2.Text := IntToStr(FileSizeByName(OpenDialog1.FileName));
end;
end;
procedure TForm1.SendFileButtonClick(Sender: TObject);
var
IncommingText: string;
Strm: TFileStream;
begin
if not CheckBox1.Checked then
begin
ShowMessage('Please connect to the Server');
Exit;
end;
if OpenDialog1.FileName = '' then
begin
ShowMessage('Please choose a file');
Exit;
end;
Strm := TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
try
IdTCPClient1.IOHandler.WriteLn(Edit1.Text + '@' + Edit2.Text + ';' + Edit3.Text + ',', TIdTextEncoding.UTF8);
IdTCPClient1.IOHandler.LargeStream := True;
IdTCPClient1.IOHandler.Write(Strm, 0 , True);
finally
Strm.Free;
end;
Memo1.Lines.Add('File Sent');
IncommingText := IdTCPClient1.IOHandler.ReadLn;
if IncommingText = 'DONE!' then begin
Memo1.Lines.Add('File ' + Edit1.Text + ' ' + Edit2.Text + ' was received successfully by the Server');
//APPLICATION.ProcessMessages;
end else
begin
Memo1.Lines.Add('File ' + Edit1.Text + ' was not received by the Server');
end;
end;
Наконец, просто к вашему сведению, вы устанавливаете для параметра AWriteByteCount
Write()
значение True, поэтому он будет передавать размер потока (как Int64
из-за LargeStream=True
) перед отправкой данных TStream
, поэтому помещая размер файла в данные WriteLn()
является избыточным.
12.12.2013