zoukankan      html  css  js  c++  java
  • WebService支持多平台上传文件的实现

     

    要使用网站上传文件,在ASP.NET的范畴,我基本上能想到的有两类,一类是通过HTTP POST请求获得文件信息,另外一类是通过WebService或者WCF之类的技术对外发布服务。

    以前做3G摄像头项目的时候,做过使用HTTP POST的方式获得照片,方式很简单,就是一个aspx文件(其实用asp也行,最开始是用asp实现的,用aspx的时候还出了点幺蛾子),只是客户端(摄像头)那边需要了解POST请求,将图片做成数据传输上来。这个方式也没什么不好的,就是无奈在集成到系统中的时候总是出点问题,想着反正还要做多种客户端,于是乎改成第二类方式。

    需求是要能够实现多个平台(PC,Android,iOS)的文件传输。

    我说用WCF吧,之前我用来着,容易上手,但是其他人觉得WCF可能不太容易与非.NET平台互通(没深入探究,但是网上看到过有人用android调用WCF的,以后有时间再探讨),于是乎老老实实的用WebService。

    Android调用webservice好像也有两种方式,我们实现的是用ksoap2调用,首先我需要编写WEBSERVICE。

    文件用什么参数传递呢?

    1. 简单暴力byte[],使用File类或者FileStream类可以很容易将文件流汇入byte数组,直接传递。
    2. 不简单但是暴力string,使用某种方式将文件变成string,再进行传输。
    3. 其他方法,类似object?或者别的什么。

    这里有序列化的知识,我还没深入体会,说说自己的看法吧:

    首先序列化个人看来就是把对象什么的变得可以存储和传输,有了这个就能够很方便的实现一些网络应用。然后就是说KSOAP2对基本的数据类型都能够序列化,我看到string了,但是也不知道支持还是不支持byte[]型。

    回到正题,干脆2个都来吧,反正也不差多少事。

    由于自己有点疑虑,所以先实现了第二种,通过某种方式---base64编码解码。通过这个编码可以将BYTE变成能够直接网络传输的string,server端收到数据之后解码就能够得到原始byte[]。以下列出web端函数。

    复制代码
    [WebMethod(MessageName = "UploadSmallString")]
            public bool UploadSmallString(string fileName, string serializedData)
            {
                try
                {
                    byte[] receivedBytes = Convert.FromBase64String(serializedData);
                    using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        fs.Write(receivedBytes, 0, receivedBytes.Length);
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    复制代码

    客户端用base64编码就可以了,网上找找很多。细心的客官可能看到函数名SmallString,对的,这个适用于文件不太大的时候传输,传输很大的文件呢?

    分块!分块传输的好处在于能够支持断点续传,说说客户端的实现思路:

    1.判断文件大小
    2.是否适用于分块传输
    3.调用服务进行操作

    然后服务器端呢,写个重载吧,可是试了试不成功,参见http://www.cnblogs.com/menglin2010/archive/2012/03/29/2421445.html中说不太支持,要改,用[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]如果改成None用以支持重载的话,又怕出现兼容性问题,老老实实的吧还。

    复制代码
    /// <summary>
            /// 使用BASE64编码接收分块传输的大文件
            /// </summary>
            /// <param name="fileName">文件名</param>
            /// <param name="serializedData">BASE64数据</param>
            /// <param name="blockSerial">用以识别文件块的ID</param>
            /// <returns>对应成功文件块ID,不成功便成-1</returns>
            [WebMethod(MessageName = "UploadBlobString", Description = "支持大文件传输的方法,blockserial为0将创建新文件,这也是默认行为")]
            public int UploadBlobString(string fileName, string serializedData, int blockSerial = 0)
            {
                try
                {
                    byte[] receivedBytes = Convert.FromBase64String(serializedData);
                    if (blockSerial == 0)
                    {
                        using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.Create))
                        {
                            fs.Write(receivedBytes, 0, receivedBytes.Length);
                        }
                    }
                    else
                    {
                        using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.Append))
                        {
                            fs.Write(receivedBytes, 0, receivedBytes.Length);
                        }
                    }
                    return blockSerial;
                }
                catch
                {
                    return -1;
                }
            }
    复制代码

    琢磨了一下,好像这个完全可以替代前一个方法,是用.NET默认参数的特性,指定blockSerial默认为0。如果客户端中断了,续传的时候从断点blockSerial开始就OK了。

    接下来说说第一种,使用bye[]的方式。

    复制代码
    [WebMethod(MessageName = "UploadSmallByte", Description = "直接发送BYTE数组存储")]
            public bool UploadSmallByte(string fileName, byte[] fileBytes)
            {
                try
                {
                    using (FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        fs.Write(fileBytes, 0, fileBytes.Length);
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    复制代码

    这种方式我没怎么测试过,但是有一个有意思的事情,就是如果ANDROID编码BASE64后的string直接传递给byte[]参数,这个函数依然可以正常工作,上传的图片还是可以正常显示,很是诡异呀,想在.net下试一试,直接由于类型不同,不能编译,以后有机会再琢磨琢磨。

    P.S. BASE64方式的代码经过测试能够在ANDROID平台和PC平台下通过,iOS等待BASE64实现(貌似没有内部的BASE64编码方法),从原理上应该没问题,欢迎大家讨论。

  • 相关阅读:
    【linux 高级网络应用】1,2-企业IP规划部署实战,ip地址和子网划分
    【linux CCNP】4,5-linux网络及OIS-TCP/IP
    【linux CCNP】3-linux网络抓包和TCP三次握手
    【linux CCNA】1和2-linux网络基础知识入门 与 tcp协议
    CephFS文件储存
    OSD纵向扩容
    CEPH之对象存储
    CEPH之块存储
    ceph_dashboard
    ceph 创建和删除osd
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3629426.html
Copyright © 2011-2022 走看看