从字节缓冲区传输到 AnsiString 时丢失数据
Losing data when transfering from Bytes Buffer to AnsiString
我正在尝试从我的 CentOS 发送一个 4063 字节的 AMR 文件(仅用于测试)VPS
nc IP 45500 < sample.amr
但是当应用程序收到它时,它只显示一个剪切数据:
1448: #!AMR-WB
Ô_Æ ÅѤm^8E•Ì^^ìÖõ¾_€°
2617:
奇怪的是:如果我编辑 AMR 文件并删除标记的字符:
然后再次发送我收到的相同 AMR 文件:
1448: #!AMR-WB
Ô_Æ ÅѤm^8E•Ì^^ìÖõ¾_€°ÀžH¯ë2Çc oÚÖɾøy$Ý
2616: ¢Khw^è“ʺ\?¬šJ£<é<'
.. 更多数据,特别是下一个 NUL 字符
这是我的 Socket 的代码 onClientRead
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
received,a: string;
size,i: Integer;
AnsiStr: String;
Bytes: array[0..2048*256] of Byte;
begin
Size := Socket.ReceiveLength;
Socket.ReceiveBuf(Bytes[0], Size);
SetString(AnsiStr, PAnsiChar(@Bytes[0]), Size);
received := IntToStr(Size)+': '+AnsiStr;
Memo1.Lines.Add(received);
Memo1.Lines.Add(' ');
end;
我相信 SetString
命令导致了这个,但不确定如何接收整个数据。我只想接收整个文件并将其复制到我这边的新 AMR 文件中。
额外:
我试图从我的服务器发送到我的电脑的文件位于:
http://techslides.com/demos/samples/sample.amr
您的代码不起作用的主要原因有两个:
您使用的是 Delphi 的 Unicode 版本,因此 string
类型映射到 UnicodeString
,而不是您期望的 AnsiString
.
在内部,TMemo.Lines.Add()
方法使用 EM_REPLACESEL
消息将字符串传递给 TMemo
window,它将输入字符串视为 null -终止。这就是为什么您的文件内容在 nul
"characters".
处被截断的原因
正如其他人在评论中所说,您试图将二进制数据显示为文本,但它不是文本。将原始二进制数据按原样保存到硬盘上的实际文件中。如果您想在 UI 中显示文件字节,请以文本安全格式显示它们,例如十六进制。
试试像这样的东西:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Socket.Data := TFileStream.Create('<some path>\sample.amr', fmCreate);
end;
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
TFileStream(Socket.Data).Free;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Size: Integer;
Bytes: TBytes;
Received: string;
begin
Size := Socket.ReceiveLength;
if Size < 1 then Exit;
SetLength(Bytes, Size);
Size := Socket.ReceiveBuf(Bytes[0], Size);
if Size < 1 then Exit;
TFileStream(Socket.Data).WriteBuffer(Bytes[0], Size);
SetLength(Received, Size*2);
BinToHex(Bytes[0], PChar(Received), Size);
Memo1.Lines.Add(IntToStr(Size) + ': ' + Received);
Memo1.Lines.Add(' ');
end;
我正在尝试从我的 CentOS 发送一个 4063 字节的 AMR 文件(仅用于测试)VPS
nc IP 45500 < sample.amr
但是当应用程序收到它时,它只显示一个剪切数据:
1448: #!AMR-WB
Ô_Æ ÅѤm^8E•Ì^^ìÖõ¾_€°
2617:
奇怪的是:如果我编辑 AMR 文件并删除标记的字符:
然后再次发送我收到的相同 AMR 文件:
1448: #!AMR-WB
Ô_Æ ÅѤm^8E•Ì^^ìÖõ¾_€°ÀžH¯ë2Çc oÚÖɾøy$Ý
2616: ¢Khw^è“ʺ\?¬šJ£<é<'
.. 更多数据,特别是下一个 NUL 字符
这是我的 Socket 的代码 onClientRead
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
received,a: string;
size,i: Integer;
AnsiStr: String;
Bytes: array[0..2048*256] of Byte;
begin
Size := Socket.ReceiveLength;
Socket.ReceiveBuf(Bytes[0], Size);
SetString(AnsiStr, PAnsiChar(@Bytes[0]), Size);
received := IntToStr(Size)+': '+AnsiStr;
Memo1.Lines.Add(received);
Memo1.Lines.Add(' ');
end;
我相信 SetString
命令导致了这个,但不确定如何接收整个数据。我只想接收整个文件并将其复制到我这边的新 AMR 文件中。
额外: 我试图从我的服务器发送到我的电脑的文件位于: http://techslides.com/demos/samples/sample.amr
您的代码不起作用的主要原因有两个:
您使用的是 Delphi 的 Unicode 版本,因此
string
类型映射到UnicodeString
,而不是您期望的AnsiString
.在内部,
TMemo.Lines.Add()
方法使用EM_REPLACESEL
消息将字符串传递给TMemo
window,它将输入字符串视为 null -终止。这就是为什么您的文件内容在nul
"characters". 处被截断的原因
正如其他人在评论中所说,您试图将二进制数据显示为文本,但它不是文本。将原始二进制数据按原样保存到硬盘上的实际文件中。如果您想在 UI 中显示文件字节,请以文本安全格式显示它们,例如十六进制。
试试像这样的东西:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Socket.Data := TFileStream.Create('<some path>\sample.amr', fmCreate);
end;
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
TFileStream(Socket.Data).Free;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Size: Integer;
Bytes: TBytes;
Received: string;
begin
Size := Socket.ReceiveLength;
if Size < 1 then Exit;
SetLength(Bytes, Size);
Size := Socket.ReceiveBuf(Bytes[0], Size);
if Size < 1 then Exit;
TFileStream(Socket.Data).WriteBuffer(Bytes[0], Size);
SetLength(Received, Size*2);
BinToHex(Bytes[0], PChar(Received), Size);
Memo1.Lines.Add(IntToStr(Size) + ': ' + Received);
Memo1.Lines.Add(' ');
end;