如何在Symbian中使用Http上传大文件

最近因为项目的关系,研究了一下在 Symbian 中使用 Http 协议上传 multipart/form-data 格式数据的实现方法。由于要求上传的数据较大,所以研究了如何在 Nokia Http Exmaple 的基础上,使用 MHTTPDataSupplier 派生类分包上传的实现。

 

1. 在实现 Http 协议的类中(以 HttpEngine 为例),需要重写下面几个函数:

void SetupConnectionL();

void IssueHTTPGetL();

void IssueHTTPPostL();

void IssueHTTPDeleteL();

void CancelTransaction();

// 上传大文件时,需要特别关注下面 4 个类

void ReleaseData();

TBool GetNextDataPart(TPtrC8& aDataPart);

TInt Reset();

TInt OverallDataSize();

在搭建初步的 HttpEngine 框架时,可以根据需求,重写 SetupConnectionL() Get Post Delete 等函数,具体的实现方法可参考 Http 协议完成。

2.Nokia Http Exmaple 适用的情况为一个 Chunk Post 的时候,如果想要上传较大的文件,需要重写上面 4 个类的实现。下面是 Http Engine 的简要工作流程:

A.       通过 OverallDataSize 函数获得上传文件的总大小,这意味着,是整个上传文件的长度,而不是每次分包上传的长度。如果 Size 错误或者 Size 大小不确定,都会引起错误。

 

B.       开始上传,将会调用 GetNextDataPart(TPtrC8& aDataPart) 得到本次上传的数据。如果是分包上传,这里是当前上传包的数据内容

 

C.       如果上传过程中出错,将会返回,并重新调用 A 。如果成功,将会 ReleaseData(); 并根据 GetNextDataPart 之前的返回值判断是否还需要调用 GetNextDataPart 。在 C 中存在很关键的一环,如果发送过程中底层出错,将会重新通过 OverallDataSize 获得上传的总大小,而进入 OverallDataSize 就表示一切操作重头再来了,所以需要在 OverallDataSize 里面重置所有的数据指针,而一般的方法通过 Reset 将数据指针指向第一块数据。如果是使用状态机的方式进行数据传送,则需要将状态置为最先一步操作的状态。

 

 

D.       每次数据传送完成,需要调用 ReleaseData() 释放之前发送的数据。在分包传输时,如果数据没有传完,需要显示调用 RHTTPTransaction NotifyNewRequestBodyPartL() 函数通知 Engine 。不然,不会进入到 GetNextDataPart

 

3. 对于 multipart 类型数据的上传,推荐采用状态机的方式。在每个状态中上传不同 bounary 的数据。对于上传大文件,也尽量控制分包大小在 100k 以内,以免内存分配不够而引发错误

 

下面是一些实现代码,有些具体的操作放在了 observer 里面进行

TBool CHttpEngine::GetNextDataPart ( TPtrC8 & aDataPart)

     {

      return iObserver .GetNextDataPart(aDataPart);

     }

void CHttpEngine::ReleaseData ()

     {

     if ( iObserver .BytesTransfered() != iOverDataSize )        

          iTransaction . NotifyNewRequestBodyPartL ();

 

     iObserver .ReleaseData();

     }

TInt CHttpEngine::Reset ()

     {

     //Reset the state

     iObserver .Reset();

     return KErrNone;

     }

TInt CHttpEngine::OverallDataSize ()

     {

     Reset();

     iOverDataSize = iObserver .OverallDataSize();

     if (0 != iOverDataSize )

          return iOverDataSize ;

     return KErrNotFound;

     }

 

部分Observer代码

----
TBool xxxx::GetNextDataPart(TPtrC8& aDataPart)
    {
    xxxx_FUNC_EX( "xxxx::GetNextDataPart" );
    if (EPostBlog == iIssueFuncType)
        {
        if (NULL != iPostImageLoc)
            {
            switch (iPostDataState)
                {
                case EPostIdle:
                    {
                    //                    User::Panic(_L("xxxx:RunL"), KErrGeneral);
                    ASSERT(0);
                    break;
                    }
                case EPostContent:
                    {
                    HBufC8* encodeContent = EscapeUtils::EscapeEncodeL(
                            *iBlogContent, EscapeUtils::EEscapeUrlEncoded);
                    CleanupStack::PushL(encodeContent);
                    TInt contentSize = encodeContent->Length();

                    iPostData = HBufC8::NewL(contentSize + 100);

                    TPtr8 postDataPtr = iPostData->Des();
                    postDataPtr.Zero();

                    //Start package
                    postDataPtr.Append(KCrlf);
                    //Status(blog) content boundary
                    postDataPtr.Append(KDataStart);
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(KStatusContent);
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(*encodeContent); //content
                    postDataPtr.Append(KCrlf);

#ifdef __WINSCW
                    xxxx_DEBUG2("postDataPtr size = %d", postDataPtr.Length());
#endif
                    iByteTransfered = postDataPtr.Length();
                    aDataPart.Set(postDataPtr);

                    CleanupStack::PopAndDestroy(encodeContent);

                    iPostDataState = EPostImageStart;
                    return EFalse;
                    }
                case EPostImageStart:
                    {
                    iPostData = HBufC8::NewL(
                            MULTIPART_IMAGE_START_STATEMENT_LEN);

                    TPtr8 postDataPtr = iPostData->Des();
                    postDataPtr.Zero();

                    //Image boundary
                    postDataPtr.Append(KDataStart);
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(KImageContent);
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(KImageContentType);
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(KCrlf);

                    aDataPart.Set(postDataPtr);
#ifdef __WINSCW
                    xxxx_DEBUG2("postDataPtr size = %d", postDataPtr.Length());
#endif       
                    iByteTransfered += postDataPtr.Length();

                    iPostDataState = EPostImage;
                    return EFalse;

                    }
                case EPostImage:
                    {
                    HBufC* encodeLoc;
                    yyyy::TransformUTF8ToUnicodeL(
                            *iPostImageLoc, &encodeLoc);

                    //Get the image's size
                    TInt imageSize;
                    iFile.Size(imageSize);

                    if (imageSize < MAX_IMG_SIZE_PER_SEND)
                        {
                        //read the image data
                        HBufC8* imageData = HBufC8::NewL(imageSize);
                        TPtr8 imagePtr(imageData->Des());
                        iFile.Read(imagePtr);

                        //
                        iFile.Close();
                        delete encodeLoc;

                        iPostData = HBufC8::NewL(imageSize + 100);

                        TPtr8 postDataPtr = iPostData->Des();
                        postDataPtr.Zero();

                        //Image data
                        postDataPtr.Copy(imagePtr);

                        delete imageData;

#ifdef __WINSCW
                        xxxx_DEBUG2("postDataPtr size = %d", postDataPtr.Length());
#endif

                        iByteTransfered += postDataPtr.Length();
                        aDataPart.Set(postDataPtr);
                        iPostDataState = EPostImageEnd;
                        return EFalse;

                        }
                    else
                        {
                        iPostData = HBufC8::NewL(MAX_IMG_SIZE_PER_SEND);

                        TPtr8 buf = iPostData->Des();
                        User::LeaveIfError(iFile.Read(buf,
                                MAX_IMG_SIZE_PER_SEND));
                        aDataPart.Set(*iPostData);

                        iFileSendBytes = 0;
                        User::LeaveIfError(iFile.Seek(ESeekCurrent,
                                iFileSendBytes));

                        if (iFileSendBytes == imageSize)
                            {
                            iFile.Close();
                            iPostDataState = EPostImageEnd;
                            }
                        else
                            {
                            iPostDataState = EPostImage;
                            }
#ifdef __WINSCW
                        xxxx_DEBUG2("postDataPtr size = %d", buf.Length());
#endif

                        iByteTransfered += buf.Length();

                        return EFalse;
                        }
                    }
                case EPostImageEnd:
                    {
                    iPostData = HBufC8::NewL(MULTIPART_IMAGE_END_STATEMENT_LEN);

                    TPtr8 postDataPtr = iPostData->Des();
                    postDataPtr.Zero();

                    //Image end
                    postDataPtr.Append(KCrlf);
                    postDataPtr.Append(KDataEnd);
                    postDataPtr.Append(KCrlf);
                    //End package

                    iByteTransfered += postDataPtr.Length();
                    aDataPart.Set(postDataPtr);

                    return ETrue;
                    }
                default:
                    {
                    User::RequestComplete(iNotifyStatus, KErrGeneral);
                    return ETrue;
                    }
                }

            }
        else
            {
            //postData contains blog content
            TBuf8<KDefaultBufferSize> buf;
            buf.Append(KStatus);

            //encode the content
            HBufC8* encodeContent = EscapeUtils::EscapeEncodeL(*iBlogContent,
                    EscapeUtils::EEscapeUrlEncoded);
            CleanupStack::PushL(encodeContent);
            buf.Append(*encodeContent);
            CleanupStack::PopAndDestroy(encodeContent);

            iPostData = buf.AllocL();
            iByteTransfered = iPostData->Length();
            aDataPart.Set(*iPostData);

            return ETrue;
            }
        }//End of if (EPostBlog == iIssueFuncType)

    //Other post operation

    iByteTransfered = iPostData->Length();
    aDataPart.Set(*iPostData);

    return ETrue;
    }

TInt xxxx::OverallDataSize()
    {
    return iPostDataSize;
    }

TInt xxxx::BytesTransfered()
    {
    return iByteTransfered;
    }

void xxxx::ReleaseData()
    {
    xxxx_FUNC_EX( "xxxx::ReleaseData" );
    delete iPostData;
    iPostData = NULL;
    }

void xxxx::Reset()
    {
    iPostDataState = EPostContent;
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值