Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.06.2012, 13:18   #1
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
Вопрос Socket. Проблема с передачей файла

Имеется
Клиент
Код:
...
  private
    { Private declarations }
    Name: string; // Имя файла
    Size: Integer; // Размер файла
    Receive: Boolean; // Режим клиента
    MS: TMemoryStream; // Буфер для файла
...
procedure TForm1.FormCreate(Sender: TObject);
begin
  Receive := False; // Режим клиента - приём команд
end;
...
procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
  Rtext: string; // Принятый текст
begin
  Rtext := Socket.ReceiveText;
  // Если клиент в режиме приёма файла, то...
  if Receive then Writing(RText) // Записываем данные в буфер
  else // Если клиент не в режиме приёма файла, то...
  if Copy(Rtext, 1, Pos('<||>', Rtext) - 1) = '10' then // Если это команда принятия файла "10", то...
  begin
    MS := TMemoryStream.Create; // Создаём буфер для файла
    Delete(Rtext, 1, Pos('<||>', Rtext) + 3); // Определяем имя файла
    Name := Copy(Rtext, 1, Pos('<||>', Rtext) - 1); // Определяем имя файла
    Delete(Rtext, 1, Pos('<||>', Rtext) + 3); // Определяем размер файла
    Size := StrToInt(Copy(Rtext, 1, Pos('<||>', Rtext) - 1)); // Определяем размер файла
    Delete(Rtext, 1, Pos('<||>', Rtext) + 3); // Удаляем последний разделитель
    Label1.Caption := 'Размер файла: ' + IntToStr(Size) + ' байт'; // Выводим размер файла
    Label2.Caption := 'Имя файла: ' + Name; // Выводим имя файла
    Receive := True; // Переводим сервер в режим приёма файла
    Writing(RText); // Записываем данные в буфер
  end;
end;

procedure TForm1.Writing(s: string);
begin
  // Если принято байт меньше размера файла, то...
  if MS.Size < Size then MS.Write(s[1], Length(s)); // Записываем в буфер
  // Выводим прогресс закачки файла
  ProgressBar1.Position := MS.Size * 100 div Size;
  StatusBar1.SimpleText := 'Принято ' + IntToStr(MS.Size) + ' из ' + IntToStr(Size);
  // Если файл принят, то...
  if MS.Size = Size then
  begin
    Receive := False; // Переводим клиента в нормальный режим
    MS.Position := 0; // Переводим каретку в начало буфера
    MS.SaveToFile(Name); // Сохраняем файл
    ClientSocket1.Socket.SendText('11'); // Посылаем команду "11", то есть файл принят
    MS.Free; // Убиваем буфер
    StatusBar1.SimpleText := 'Файл принят';
  end;
end;
Сервер
Код:
...
procedure TForm1.Button1Click(Sender: TObject);
var 
  Size: integer;
  P: ^Byte;
begin
  MS := TMemoryStream.Create; // Создаём буфер для файла
  MS.LoadFromFile(Edit1.Text); // Загружаем файл в буфер
  ServerSocket1.Socket.Connections[0].SendText('10<||>' + Edit1.Text + '<||>' + IntToStr(MS.Size) + '<||>'); // Посылаем информацию о файле (файл и размер)
  MS.Position := 0; // Переводим каретку в начало файла
  P := MS.Memory; // Загружаем в переменную "P" файл
  Size := ServerSocket1.Socket.Connections[0].SendBuf(P^, MS.Size); // Посылаем файл
  // Выводим прогресс
  ProgressBar1.Position := Size * 100 div MS.Size;
  StatusBar1.SimpleText := 'Отправлено ' + IntToStr(Size) + ' из ' + IntToStr(MS.Size) + ' байт';
end;
...
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  // Если клиент принял файл, то...
  if Socket.ReceiveText = '11' then
  begin
    StatusBar1.SimpleText := 'Клиент принял файл';
    MS.Free; // Убиваем буфер
  end;
end;
В Delphi 7 файл передаётся замечательно, в Delphi 2010 нет. Отправляю *.txt файл с содержимым 000, а сохраняется файл с содержимым 0 0 или ABC, а сохраняется A B, или АБВ, а сохраняется . В чём дело?
Добавлено. Оказывается всё дело в TMemoryStream. Содержимое текстового файла передаётся и получается нормально, но сохраняется некорректно. Что такого натворили в TMemoryStream в Delphi 2010 и как решить данную проблему?

Последний раз редактировалось Shouldercannon; 10.06.2012 в 13:49.
Shouldercannon вне форума Ответить с цитированием
Старый 10.06.2012, 13:57   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

memorystream тут не при чем, просто строки стали юникодными (каждый символ - 2 байта), а вы продолжаете работать с ними как с однобайтовыми:

Код:
MS.Write(s[1], Length(s))
Поменяйте s: string на s: AnsiString как минимум.

Update: в кодгиар не совсем индусов набрали, ReceiveText возвращает AnsiString, так что и Rtext: string; тоже на AnsiString меняйте, иначе будут удивительные чудеса с кодировкой происходить.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 10.06.2012 в 14:26.
veniside вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
C/C++ проблема с передачей ДМУ Akkoks Общие вопросы C/C++ 3 12.06.2011 13:43
Проблема с передачей( фтпуд17 Свободное общение 5 27.01.2011 11:23
Проблема с передачей данных tools Общие вопросы C/C++ 5 25.12.2010 14:49
Проблема с передачей файла BleStaR C++ Builder 1 15.02.2010 20:37
Проблема с передачей куки arwm Работа с сетью в Delphi 7 28.12.2007 23:44