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编码方法),从原理上应该没问题,欢迎大家讨论。

  • 相关阅读:
    Nim or not Nim? hdu3032 SG值打表找规律
    Maximum 贪心
    The Super Powers
    LCM Cardinality 暴力
    Longge's problem poj2480 欧拉函数,gcd
    GCD hdu2588
    Perfect Pth Powers poj1730
    6656 Watching the Kangaroo
    yield 小用
    wpf DropDownButton 源码
  • 原文地址:https://www.cnblogs.com/podolski/p/3628210.html
Copyright © 2011-2022 走看看