【问题标题】:Delphi 2007 & Updated Indy 10Delphi 2007 和更新的 Indy 10
【发布时间】:2013-12-12 21:25:53
【问题描述】:

我正在发送带有英文文件名的正确文件(doc、pdf、xls),但是当我发送带有希腊文件名的文件时,我正在服务器端?????????文件名字符和错误消息 Socket Error 10053,软件导致连接中止。有没有针对此类问题的解决方案。

代码:

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;

【问题讨论】:

    标签: delphi delphi-2007 indy10


    【解决方案1】:

    Indy 的默认文本编码是 ASCII(因为大多数 Internet 协议仍然主要基于 ASCII,除非它们定义了额外的扩展来支持 Unicode)。这就是为什么非 ASCII 字符会得到 ? 的原因。要发送非 ASCII 字符,您需要告诉 Indy 使用哪种文本编码与您正在交换的字符兼容。 UTF-8 通常是最好的选择。您可以通过三种方式做到这一点:

    1. 在IdGlobal 单元中设置全局GIdDefaultTextEncoding 变量。默认设置为encASCII,你可以改为encUTF8:

      procedure TForm1.FormCreate(Sender: TObject);
      begin
        GIdDefaultTextEncoding := encUTF8;
      end;
      
    2. 将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;
      
    3. 将TIdTextEncoding.UTF8(或IndyTextEncoding_UTF8)直接传递给WriteLn()的AByteEncoding参数:

      IdTCPClient1.IOHandler.WriteLn(..., TIdTextEncoding.UTF8);
      // or:
      // IdTCPClient1.IOHandler.WriteLn(..., IndyTextEncoding_UTF8);
      

    请记住,您使用的是 Ansi 版本的 Delphi,其中 string 映射到 AnsiString,因此 Indy 必须对 AnsiString 数据执行额外的 Ansi 到 Unicode 转换,然后才能应用指定的文本编码以产生它传输的字节。通常,Indy 使用操作系统的默认 Ansi 编码来处理初始转换(因此,如果您的 AnsiString 数据是希腊语编码的,并且您的操作系统设置为希腊语,您会没事的),但是您可以使用 TIdIOHandler.DefAnsiEncoding 属性,或WriteLn() 的ASrcEncoding 参数,如果您需要指定您的AnsiString 数据使用不同的编码。

    至于您的套接字错误,没有看到导致错误的调用堆栈,或者至少没有看到您的代码的哪一行引发了错误,这很难解决。我的猜测是它与您在 finally 块内调用 ReadLn() 有关,无论 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;
    

    最后,仅供参考,您将Write() 的AWriteByteCount 参数设置为True,因此它将在发送@ 之前传输流大小(因为Int64,因为LargeStream=True) 987654353@ 数据,所以将文件大小放在WriteLn() 数据中是多余的。

    【讨论】:

    • 非常感谢您的回答!
    猜你喜欢
    • 2012-10-28
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多