Инди текст по умолчанию кодировку 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
, если вы используете Инди 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 Дельфы, где string
карты для AnsiString
, и, таким образом, Инди должен выполнить дополнительное преобразование Ansi-к-Unicode данных AnsiString, прежде чем он может применить указанный текст кодирование для создания передаваемых им байтов. Как правило, 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;
Наконец, просто FYI, вы устанавливаете параметр Write()
в True AWriteByteCount
, поэтому он будет передавать размер потока (как Int64
из-за LargeStream=True
) перед отправкой данных TStream
, поэтому размер файла в WriteLn()
является избыточным.
Большое спасибо за ваш ответ! – VaVel