DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: tkzcol
今日帖子: 4
在线用户: 2
导航: 论坛 -> 移动应用开发 斑竹:flyers,iamdream  
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/18 20:50:18
标题:
IDHttpServer中,怎么样才能从收到的流中(WebKitFormBoundary),解出图片呢? 浏览:1384
加入我的收藏
楼主: 我客户端是用HBuildx, 服务端是用IDHttpServer,

我客户端上传一个图片, 服务端如果不做任何处理,直接将流保存为文件, 用记事本打开,发现是以下格式


------W ebKit FormBo unda ry6a7XEkgemCOp1yuE
Con tent-Disp osition: f orm-da ta; name="da ta"; file name="a. bmp"
Conte nt-Type: im age /bmp 

BM6*********图片数据**********
------We bKit FormB ound ary6a7XEkgemCOp1yuE--

(上述加了不少空格,以便能在论坛上发表, 否则论坛不支持)



(我自已尝试用以下方法,想把中间的图片数据取出来,

aStrList.LoadFromStream(ARequestInfo.PostStream);
aStrList.Delete(aStrList.Count-1); //删除最后一行
aStrList.Delete(3);          //删除第4行
aStrList.Delete(2);          //删除第3行
aStrList.Delete(1);          //删除第2行
aStrList.Delete(0);          //删除第1行

aStrList.SaveToFile(sFileName);  

但这样, 保存出来的文件,是0字节....

本人对流方面, 基本是小白. 恳请大家指点一下. 非常感谢.
----------------------------------------------
...
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/18 21:46:08
1楼: procedure TForm1.IdHTTPServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  FileStream: TFileStream;
begin
  if ARequestInfo.PostStream <> nil then
  begin
    ARequestInfo.PostStream.Position := 0;
    FileStream := TFileStream.Create('1.jpg', fmCreate);
    FileStream.CopyFrom(ARequestInfo.PostStream, ARequestInfo.PostStream.Size); { Copy 流 }
    FileStream.Free;
  end;
end;

我用这种方式, 接收到的图片, 会有前缀和后缀

------W ebKit FormBo unda ry6a7XEkgemCOp1yuE
Con tent-Disp osition: f orm-da ta; name="da ta"; file name="a. bmp"
Conte nt-Type: im age /bmp 

BM6*********图片数据**********
------We bKit FormB ound ary6a7XEkgemCOp1yuE--



如何在流中, 定位真实文件的起始和长度呢?
----------------------------------------------
...
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/18 22:12:36
2楼: 上述字符串中,我故意加了几个空格, 因为,如果不加的话,盒子发不了
----------------------------------------------
...
作者:
男 xxz1314 (xxz1314) ★☆☆☆☆ -
普通会员
2022/12/19 9:50:12
3楼: 自己直接吧图片文件转换成流然后用你服务端的代码保存成文件,再看看文件是否正常,意思就是不经过idhtttserver,看能不能正常使用,如果可以再拆分代码放到idhttpserver上不就可以了
----------------------------------------------
-
作者:
男 xxz1314 (xxz1314) ★☆☆☆☆ -
普通会员
2022/12/19 10:06:03
4楼: https://www.cnblogs.com/hjk1124/p/15177240.html
----------
参考上面地址的方法看看
----------------------------------------------
-
作者:
男 xxz1314 (xxz1314) ★☆☆☆☆ -
普通会员
2022/12/19 10:07:59
5楼: contentType: 'application/json;charset=UTF-8' 设置
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/12/19 21:23:21
6楼: 如果你的客户端是标准的浏览器,那么,它发出来的文件上传到 HTTP,就应该符合标准的 HTTP 的协议。

因此,你的 IdHTTPServer 收到的,就应该是标准的 http 的东西,里面的内容以及文件,应该是符合 MIME 规范的。

Indy 有几个控件是用来处理 MIME 的,你可以看看。比如,TIdMessage 这个控件。

如果你用这样的控件,它帮你解析好 HTTP 文件,从里面把文件单独处理了。

当然,如果你要自己处理 HTTP 文本,自己分析字符串,找到文件开始的地方,也行。问题是,你要知道你收到的文件是二进制流,还是 BASE 编码的字符串(或者其它编码)。

如果文件在 HTTP 内容里面是二进制流的方式存在,你用 StringList 是没办法处理的。

如果是编码后的文本,可以用 StringList 处理。你的 StringList 处理的代码有问题:

aStrList.LoadFromStream(ARequestInfo.PostStream);

你这里 LoadFromStream 以后,你直接 SaveToFile 为一个文本文件,用文本编辑器打开,看看内容是不是正确的。先保证里面的内容正确,再说后面的处理。
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/12/19 21:33:07
7楼: 另外,你说保存为文件字节数是 0,也许原因就是你的 StringList.LoadFrom
Stream 本身没有成功。在执行这个操作之前,你试试:

ARequestInfo.PostStream.Position := 0;
aStrList.LoadFromStream(ARequestInfo.PostStream);
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/12/21 1:49:07
8楼: an observation:
-- maybe be necessary look at "signature" on stream to search a "bitmap signature"

0) read your full Stream
1) try find bytes: [66,77] = ...BM...
2) put your Stream in this position
3) save your Stream in disk!


  for var i: int64 := 0 to ((AMemoryStream.Size div 2) - 1) do
    begin
      AMemoryStream.Read(LBuffer, 2);
      //
      if (LBuffer[0]=66) and (LBuffer[1]=77) then
         // this Stream "CAN BE" a bitmap...
    ...
此帖子包含附件:
PNG 图像
大小:18.7K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2022/12/21 18:36:52
9楼: 这是标准的Post过来的数据格式,我认为解析方法有几种:
1,用indy自带的TIdMessageDecoderMIME来解。
2,用Alcinoe中的demo来解。
3,用delphi中Web相关组件来解。
以上限制在上传的文件在2G内,当然,也可以自己写复杂的代码来存更大的文件。

4,不用POST,用 PUT。

5,用 Delphi-Cross-socket 来做服务器,硬盘够就行。

附件是indy的一个例子
此帖子包含附件:sail2000_20221221183652.txt 大小:7.6K
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/24 19:34:18
10楼:
----------------------------------------------
...
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/24 19:34:43
11楼:
----------------------------------------------
...
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/24 19:35:13
12楼: 在大家的指导下, 最后我采用TIdMessageDecoderMIME的方法,

具体写法,我还在整理中, 等整理好, 我会在这个贴子里, 再发出来.

只是目前, 在文件名提取时, 不懂如何转码:

我用记事本打开流文件:

filename=QQ鎴浘20221212002717.png

这里的fileName是乱码, 原文件名是: QQ截图20221212002717.png

哪位指点一下,该如何转化:

QQ鎴浘20221212002717.png ===> QQ截图20221212002717.png 

(我自已研究好好久,用UTF8等乱转, 都试不对.)
----------------------------------------------
...
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2022/12/26 14:31:15
13楼: 好,我整理了一下, 采用TIdMessageDecoderMIME
(但没有解决文件名乱码问题)


  I := 0;

  If ARequestInfo.PostStream <> nil then
  begin
    ARequestInfo.PostStream.Position := 0;
    msgEnd := False;


    boundary := ExtractHeaderSubItem(ARequestInfo.ContentType, 'boundary',QuoteHTTP);
    startboundary := '--' + boundary;
    repeat
      tmp := ReadLnFromStream(ARequestInfo.PostStream, -1, True);
    until tmp = startboundary;


    Decoder := TIdMessageDecoderMIME.Create(nil);
    try
      TIdMessageDecoderMIME(Decoder).MIMEBoundary := boundary;


      tsValues := TStringList.Create;
      try
        repeat
          Decoder.SourceStream := ARequestInfo.PostStream;
          Decoder.FreeSourceStream := False;
          Decoder.ReadHeader;
          Inc(I);
          case Decoder.PartType of
          mcptAttachment, mcptText:
          begin
          ms := TMemoryStream.Create;
          try
          ms.Position := 0;
          newdecoder := Decoder.ReadBody(ms, msgEnd);
          tmp := Decoder.Headers.Text;
          fname := Decoder.Filename;
          Decoder.Free;
          Decoder := newdecoder;
          if Decoder <> nil then
          TIdMessageDecoderMIME(Decoder).MIMEBoundary := boundary;
          //sleep(100);  盒子朋友: 原文有这个代码, 但我不知道它有什么用处, 就隐掉了.
          if fname <> '' then
          begin
          ms.SaveToFile(fname);
          // msgEnd := true;
          end
          else
          begin
          ms.SaveToFile(IntToStr(I) + '.txt');
          end;
          finally
          ms.Free;
          end;
          end;
          mcptIgnore:
          Begin
          FreeAndNil(Decoder);
          Decoder := TIdMessageDecoderMIME.Create(nil);
          TIdMessageDecoderMIME(Decoder).MIMEBoundary := boundary;
          End;
          mcptEOF:
          begin
          FreeAndNil(Decoder);
          msgEnd := True
          end;
          end;


        until (Decoder = nil) or (msgEnd);
      finally
        tsValues.Free;
      end;
    finally
      FreeAndNil(Decoder);
    end;
  end;
----------------------------------------------
...
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2023/1/2 15:51:14
14楼: 乱码不关这里事,只要你这里使用utf8就行,要在程序构建之初就指定 indy 套件使用一个编码,但我没在电脑前,忘了,回去找下。
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2023/1/2 16:07:23
15楼: 就一句代码:
IdGlobal.GIdDefaultTextEncoding := encUTF8;

来源于indy作者的回答:
https://stackoverflow.com/questions/70171786
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 aknightchen (.) ★☆☆☆☆ -
盒子活跃会员
2023/1/2 16:20:37
16楼: 感谢 sail2000 (小帆工作室)的指点!!!!





最后,我总结一下代码:



  I := 0;

  If ARequestInfo.PostStream <> nil then
  begin
    ARequestInfo.PostStream.Position := 0;
    msgEnd := False;


    boundary := ExtractHeaderSubItem(ARequestInfo.ContentType, 'boundary',QuoteHTTP);
    startboundary := '--' + boundary;
    repeat
      tmp := ReadLnFromStream(ARequestInfo.PostStream, -1, True);
    until tmp = startboundary;

    IdGlobal.GIdDefaultTextEncoding := encUTF8; //加上sail2000 (小帆工作室),这一句,就行了Decoder.Filename就能正确显示汉字了

    Decoder := TIdMessageDecoderMIME.Create(nil);
    try
      TIdMessageDecoderMIME(Decoder).MIMEBoundary := boundary;


      tsValues := TStringList.Create;
      try
        repeat
          Decoder.SourceStream := ARequestInfo.PostStream;
          Decoder.FreeSourceStream := False;
          Decoder.ReadHeader;
          Inc(I);
          case Decoder.PartType of
          mcptAttachment, mcptText:
          begin
          ms := TMemoryStream.Create;
          try
          ms.Position := 0;
          newdecoder := Decoder.ReadBody(ms, msgEnd);
          tmp := Decoder.Headers.Text;
          fname := Decoder.Filename;  //********** here
          Decoder.Free;
          Decoder := newdecoder;
          if Decoder <> nil then
          TIdMessageDecoderMIME(Decoder).MIMEBoundary := boundary;

          if fname <> '' then
          begin
          ms.SaveToFile(fname);
          end
          else
          begin
          ms.SaveToFile(IntToStr(I) + '.txt');
          end;
          finally
          ms.Free;
          end;
          end;
          mcptIgnore:
          Begin
          FreeAndNil(Decoder);
          Decoder := TIdMessageDecoderMIME.Create(nil);
          TIdMessageDecoderMIME(Decoder).MIMEBoundary := boundary;
          End;
          mcptEOF:
          begin
          FreeAndNil(Decoder);
          msgEnd := True
          end;
          end;


        until (Decoder = nil) or (msgEnd);
      finally
        tsValues.Free;
      end;
    finally
      FreeAndNil(Decoder);
    end;
  end;
----------------------------------------------
...
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行89.84375毫秒 RSS