Arhn - архитектура программирования

Delphi 2007 и обновленный Indy 10

Я отправляю файлы в порядке (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

Кодировкой текста Indy по умолчанию является 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, если вы используете 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) непосредственно в параметр AByteEncoding WriteLn():

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

Имейте в виду, что вы используете Ansi-версию Delphi, где string сопоставляется с AnsiString, и, таким образом, Indy должен выполнить дополнительное преобразование данных AnsiString из Ansi в Unicode, прежде чем он сможет затем применить указанную текстовую кодировку для получения байтов. передает. Как правило, 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;

Наконец, просто к вашему сведению, вы устанавливаете для параметра AWriteByteCount Write() значение True, поэтому он будет передавать размер потока (как Int64 из-за LargeStream=True) перед отправкой данных TStream, поэтому помещая размер файла в данные WriteLn() является избыточным.

12.12.2013
  • Большое спасибо за ваш ответ! 13.12.2013
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..