Delphi 2007和更新的Indy 10

3

我正在发送一些文件(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;
1个回答

6

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

  1. set the global GIdDefaultTextEncoding variable in the IdGlobal unit. It is set to encASCII by default, you can set it to encUTF8 instead:

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      GIdDefaultTextEncoding := encUTF8;
    end;
    
  2. set the TIdIOHandler.DefStringEncoding property to TIdTextEncoding.UTF8 (or IndyTextEncoding_UTF8 if you are using Indy 10.6+):

    procedure TForm1.IdTCPClient1Connected(Sender: TObject);
    begin
      IdTCPClient1.IOHandler.DefStringEncoding := TIdTextEncoding.UTF8;
      // or:
      // IdTCPClient1.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
    end;
    
  3. pass TIdTextEncoding.UTF8 (or IndyTextEncoding_UTF8) directly to the AByteEncoding parameter of WriteLn():

    IdTCPClient1.IOHandler.WriteLn(..., TIdTextEncoding.UTF8);
    // or:
    // IdTCPClient1.IOHandler.WriteLn(..., IndyTextEncoding_UTF8);
    
请记住,您正在使用Delphi的Ansi版本,其中映射到AnsiString,因此Indy必须在将指定的文本编码应用于生成它发送的字节之前执行Ansi-to-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,因此它将在发送 TStream 数据之前传输流大小(作为 Int64,因为 LargeStream=True),因此在 WriteLn() 数据中放置文件大小是多余的。

非常感谢您的回答! - VaVel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接