书籍文库  |  文档资料  |  最近更新  |  MAP  |  TAG  | 
注册
手机版
就爱阅读网
当前位置:首页 > 电脑办公 > 电脑设计 > 程序设计 > D2010,indy10.5.5,一些问题解决方法

D2010,indy10.5.5,一些问题解决方法

分享人:beiqiao 来源:互联网 时间:2018-10-15 11:22:49 阅读:0

  刚从D7转过来有点不习惯,到发贴时都没搞懂string,ansistring,widestring的区别与具体使用环境。

  这里主要记录一些在D2010中使用自带INDY10.5.5  post网站的一些问题(主要用于发贴)。

  首先,与大家一样,遇到的是使用TIdMultiPartFormDataStream,post中文变乱码(这个乱码不是UTF8那种乱码,是一串“口”),网上说把IdMultipartFormData.pas中的IdRead函数修改,如下:

复制代码
function TIdMultiPartFormDataStream.IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint;
var
LTotalRead: Integer;
LCount: Integer;
LBufferCount: Integer;
LRemaining : Integer;
LItem: TIdFormDataField;
begin
if not FInitialized then begin
FInitialized := True;
FCurrentItem := 0;
SetLength(FInternalBuffer, 0);
end;

LTotalRead := 0;
LBufferCount := 0;

while (LTotalRead < ACount) and ((FCurrentItem < FFields.Count) or (Length(FInternalBuffer) > 0)) do begin
if (Length(FInternalBuffer) = 0) and not Assigned(FInputStream) then begin
LItem := FFields.Items[FCurrentItem];
AppendString(FInternalBuffer, LItem.FormatField, TEncoding.Default);

if Assigned(LItem.FieldObject) then begin
if (LItem.FieldObject is TStream) then begin
FInputStream := TStream(LItem.FieldObject);
FInputStream.Position := 0;
end else begin
if (LItem.FieldObject is TStrings) then begin
AppendString(FInternalBuffer, TStrings(LItem.FieldObject).Text, TEncoding.Default);
Inc(FCurrentItem);
end;
end;
end else begin
Inc(FCurrentItem);
end;
end;

if Length(FInternalBuffer) > 0 then begin
if Length(FInternalBuffer) > (ACount - LBufferCount) then begin
LCount := ACount - LBufferCount;
end else begin
LCount := Length(FInternalBuffer);
end;

if LCount > 0 then begin
LRemaining := Length(FInternalBuffer) - LCount;
CopyTIdBytes(FInternalBuffer, 0, VBuffer, LBufferCount, LCount);
if LRemaining > 0 then begin
CopyTIdBytes(FInternalBuffer, LCount, FInternalBuffer, 0, LRemaining);
end;
SetLength(FInternalBuffer, LRemaining);
LBufferCount := LBufferCount + LCount;
FPosition := FPosition + LCount;
LTotalRead := LTotalRead + LCount;
end;
end;

if Assigned(FInputStream) and (LTotalRead < ACount) then begin
LCount := TIdStreamHelper.ReadBytes(FInputStream,VBuffer, ACount - LTotalRead, LBufferCount);
if LCount < (ACount - LTotalRead) then begin
FInputStream.Position := 0;
FInputStream := nil;
Inc(FCurrentItem);
SetLength(FInternalBuffer, 0);
AppendString(FInternalBuffer, #13#10);
end;

LBufferCount := LBufferCount + LCount;
LTotalRead := LTotalRead + LCount;
FPosition := FPosition + LCount;
end;

if FCurrentItem = FFields.Count then begin
AppendString(FInternalBuffer, PrepareStreamForDispatch, TEncoding.Default);
Inc(FCurrentItem);
end;
end;
Result := LTotalRead;
end;
复制代码

红色部分是修改部分,在调用AppendString时补齐第三个参数,值为 TEncoding.Default  但是未见成效。有成功的请告诉我应该怎么做,谢谢。

 

最后无法,我使用了一个精简的TMsMultiPartFormDataStream类,源码如下:

 

View Code

注意,其中的字符串类型全是AnsiString,这个类和indy的TIdMultiPartFormDataStream用法一样。

用这个类添加中文,post后不会是乱码,尚不明原因,求解释。

  接下来的问题是,post UTF8编码问题,在2009以前,str:=UTF8Encode('字符串'),会得到一个看着像乱码的字符串,这是正确的,但是在2010中,str的结果还是“字符串”,所以用抓包工具看到的中文实际上也是编码不成功的,在2010中想要得到正确的utf8字符串,应该:str:=UTF8EncodeToShortString('字符串'); 这个函数只能针对长度不超过255的中文有效,超过255的需要用下面的函数:

复制代码
function Utf8Encode(const US: UnicodeString): AnsiString;
var
L: Integer;
begin
Result := '';
if US = '' then Exit;
L := Length(US);
SetLength(Result, L *3);
L := UnicodeToUtf8(PAnsiChar(Result), Length(Result) + 1, PWideChar(US), L);
if L=0 then
Result:='';
end;
复制代码

  上面的函数不是system的utf8Encode,是根据自己需要改编自UTF8EncodeToShortString 和 UTF8Encode,其中SetLength(Result, L *3);长度X3是因为UTF-8长度为3。

 其中原理我也不清楚,反正这样用没错,至于原理,还请知道的人告知,谢谢。 

  最后一个是GET UTF8编码问题,在d7中,我经常这样写:

  str:=http.get(url);

  str:=utf8toansi(url);(utf8toansi不是系统自带的函数,是自己写的,系统自带的utf8toansi其实是调用utf8decode,大多时候会把字符串变成空)

  在d2010中,上面的方式行不通,需要用到TStringStream,如果确实是utf8编码则,st:=tStringStream.create('',TEncoding.UTF8); 如果不确定返回数据的编码,则先

 http.get(url,st);

 //然后判断编码

  isutf8:=checkencoding(st.DataString,http.Response.ContentType);

  if isutf8 then

    str:=utf8tostring(st.DataString);

  当然,这样也不是最完美的解决方法,经过utf8tostring后,一样会有少数字符是“?”,以下附上自己用的checkEncoding;

复制代码
function  CheckEncoding(s,ContentType:string):Boolean;
var
per:TPerlRegEx;
begin
if ansicontainstext(ContentType,'charset=utf-8') then
begin
result:=True;
end
else
begin
per:=TPerlRegEx.Create(nil);
per.Options:=[preCaseLess];
per.Subject:=s;
per.RegEx:='<meta[\S\s]*?charset=(.*)>';
if per.Match then
if AnsiContainsText(per.MatchedExpression,'UTF-8') then
begin
result:=True;
end;
freeandnil(per);
end;
end;
复制代码

  以上只是个人拙见,欢迎斧正。


百度搜索“就爱阅读”,专业资料,生活学习,尽在就爱阅读网92to.com,您的在线图书馆!

热点阅读

网友最爱