2013-12-12 3 views
3

Я отправляю файлы в порядке (doc, pdf, xls) с английскими именами файлов, но когда я отправляю файлы с греческими именами файлов, я получаю на стороне сервера ????????? символов для имени файла & сообщение об ошибке Socket Error 10053, программное обеспечение вызвало прерывание соединения. Есть ли решение для такого рода проблем.Delphi 2007 & Обновленный Indy 10

Код:

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; 
    Fstream := TFileStream.Create(OpenDialog1.FileName, fmopenread); 
    Edit2.Text := inttostr(Fstream.Size); 
    Fstream.Position := 0; 
    FreeandNil(FStream); 
    //Fstream.Free; 
    end; 
end; 

procedure TForm1.SendFileButtonClick(Sender: TObject); 
var 
    IncommingText: string; 
begin 
    if (opendialog1.filename<>'') and (CheckBox1.Checked = True) then begin 
    IdTCPClient1.iohandler.writeln(edit1.text + '@' + edit2.text + ';' + edit3.text + ','); 
    Sleep(2000); 
    try 
     IdTCPClient1.IOHandler.largestream:=true; 
     Fstream := TFileStream.Create(OpenDialog1.FileName, fmopenread); 
     IdTCPClient1.IOHandler.Write(Fstream, 0 ,true); 
    finally 
     Fstream.Position := 0; 
     FreeandNil(FStream); 
     //Fstream.Free; 
     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; //try - finally 
    end else begin 
    showmessage('Please choose a file Or Try to connect to the Server'); 
    end; 
end; 

ответ

6

Инди текст по умолчанию кодировку ASCII (поскольку большинство протоколов Интернета по-прежнему в значительной степени на основе ASCII, если они не определяют дополнительные расширения для поддержки Unicode). Вот почему вы получаете ? для символов, отличных от ASCII. Чтобы отправить символы, отличные от ASCII, вам нужно указать Indy, какую кодировку текста использовать, совместимую с символами, которые вы обмениваете. UTF-8, как правило, лучший выбор для этого. Есть три способа сделать это:

  1. установить глобальную переменную GIdDefaultTextEncoding в IdGlobal блоке. Он устанавливается encASCII по умолчанию, вы можете установить его encUTF8 вместо:

    procedure TForm1.FormCreate(Sender: TObject); 
    begin 
        GIdDefaultTextEncoding := encUTF8; 
    end; 
    
  2. установить 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; 
    
  3. передать TIdTextEncoding.UTF8 (или IndyTextEncoding_UTF8) непосредственно на параметр AByteEncodingWriteLn():

    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() является избыточным.

+0

Большое спасибо за ваш ответ! – VaVel

Смежные вопросы