简体   繁体   English

Delphi 2007和更新的Indy 10

[英]Delphi 2007 & Updated Indy 10

I am sending alright files (doc, pdf, xls) with english filenames but when I am sending files with greek filenames I am getting on server side ????????? 我正在发送带有英文文件名的文件(doc,pdf,xls),但是当我发送带有希腊文件名的文件时,我正在服务器端上面????????? characters for filename & the error message Socket Error 10053, software caused connection abort. 文件名和错误消息的字符Socket Error 10053,软件导致连接中止。 Is there a solution for this kind of problem. 是否有解决此类问题的方法。

Code: 码:

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;

Indy's default text encoding is ASCII (because the majority of Internet protocols are still largely ASCII based, unless they define extra extensions to support Unicode). Indy的默认文本编码是ASCII(因为大多数Internet协议仍主要基于ASCII,除非它们定义额外的扩展以支持Unicode)。 That is why you are getting ? 这就是你得到的原因? for non-ASCII characters. 对于非ASCII字符。 To send non-ASCII characters, you need to tell Indy which text encoding to use that is compatible with the characters you are exchanging. 要发送非ASCII字符,您需要告诉Indy要使用的文本编码与您要交换的字符兼容。 UTF-8 is usually the best choice for that. UTF-8通常是最佳选择。 There are three ways you can do that: 有三种方法可以做到这一点:

  1. set the global GIdDefaultTextEncoding variable in the IdGlobal unit. IdGlobal单元中设置全局GIdDefaultTextEncoding变量。 It is set to encASCII by default, you can set it to encUTF8 instead: 它默认设置为encASCII ,您可以将其设置为encUTF8

     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+): TIdIOHandler.DefStringEncoding属性设置为TIdTextEncoding.UTF8 (如果使用的是Indy IndyTextEncoding_UTF8则设置为TIdIOHandler.DefStringEncoding ):

     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() : 通过TIdTextEncoding.UTF8 (或IndyTextEncoding_UTF8直接地)到AByteEncoding的参数WriteLn()

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

Keep in mind that you are using an Ansi version of Delphi, where string maps to AnsiString , and thus Indy has to perform an additional Ansi-to-Unicode conversion of AnsiString data before it can then apply the specified text encoding to produce the bytes it transmits. 请记住,您使用的是Ansi版本的Delphi,其中string映射到AnsiString ,因此Indy必须对AnsiString数据执行额外的Ansi-to-Unicode转换,然后才能应用指定的文本编码来生成字节数传输。 Typically, Indy uses the OS's default Ansi encoding to handle that initial conversion (so if your AnsiString data is Greek encoded, and your OS is set to Greek, you will be fine), however you can use the TIdIOHandler.DefAnsiEncoding property, or the ASrcEncoding parameter of WriteLn() , if you need to specify that your AnsiString data is using a different encoding. 通常,Indy使用操作系统的默认Ansi编码来处理初始转换(因此,如果您的AnsiString数据是希腊语编码,并且您的操作系统设置为希腊语,那么您会没问题),但是您可以使用TIdIOHandler.DefAnsiEncoding属性,或者ASrcEncoding WriteLn() ASrcEncoding参数,如果您需要指定您的AnsiString数据使用不同的编码。

As for your socket error, without seeing a call stack leading up to the error, or at least which line of your code is raising it, that is difficult to troubleshoot. 至于你的套接字错误,没有看到导致错误的调用堆栈,或者至少代码的哪一行提升它,这很难排除故障。 My guess is that it is related to you calling ReadLn() inside of the finally block regardless of whether WriteLn() or Write() actually succeeded. 我的猜测是,无论WriteLn()Write()实际上是否成功,它都与你在finally块中调用ReadLn()有关。 That code needs to be moved out of the finally block, it does not belong there. 该代码需要移出finally块,它不属于那里。

Try something more like this instead: 尝试更像这样的东西:

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;

Lastly, just an FYI, you are setting the AWriteByteCount parameter of Write() to True, so it is going to transmit the stream size (as an Int64 because of LargeStream=True ) before then sending the TStream data, so putting the file size in the WriteLn() data is redundant. 最后,只是一个FYI,您将Write()AWriteByteCount参数设置为True,因此它将传输流大小(因为LargeStream=True而作为Int64 ),然后发送TStream数据,因此放入文件大小在WriteLn()数据中是多余的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM