精华内容
下载资源
问答
  • QQ网络硬盘上传控件

    2012-09-16 10:11:59
    最近从腾迅下载QQ安装之后,把文件上传到QQ网盘上,老是提醒上传文件出错“找不到控件,请安装最新版本QQ”,其实质上是没有安装这个QQ网络硬盘上传控件,下载安装之后,马上就可以解决问题.
  • HTTP文件上传控件

    2011-04-16 11:30:14
    示例下载:http://www.ncmem.com/download/HttpUploaderDemo.rar 在线演示:http://www.ncmem.com/products/http-uploader/demo/index.html 升级日志:...
  • FTP文件上传控件(FtpUploader)

    热门讨论 2011-04-16 11:32:19
    新颖网络FTP文件上传控件是一个专门针对大文件传输而制定的解决方案。它能够帮助开发者实现文件断点续传和文件批量上传功能。特别适合有大文件上传需求的站点,例如视频文件上传,大型资源分享网站,网盘网站。与...
  • 想知道上传控件怎么玩的,就来免费下载吧,促进学习,大家交流而已 如有疑难问题加我QQ 912019136
  • 程序更新控件 上传 下载 C/S程序更新控件 1、程序运行数据库平台:SQL 2000(推荐) 2、首次运行按住F8,配置好数据库连接,再去执行“P_update.exe”文件 3、调用“P_update.exe”时,传入参数:“UP”表示上传;...
  • JSP大文件上传控件-access-utf8

    热门讨论 2012-08-22 14:22:31
    镜像下载(JSP):cab安装包,开发文档,ASP.NET-ACCESS示例,JSP-ACCESS示例(GB2312),JSP-ACCESS示例(UTF-8),JSP-Sql2005示例(UTF-8),JSP-MySQL示例(UTF-8) 镜像下载(PHP):MySQL示例(UTF-8) 问题反馈:...
  • 网页文件上传控件,支持4G以上超大文件传输,随时停止,支持断点续传功能,支持用户自制界面。 与您的网页系统进行无缝整合,使您的系统可自如地上传文件,并能及时获取与上传文件相关的各种信息。控件提供各种...
  • 下载了这个组件后做了一些修改并应用了ajax技术,你们可以去今天又做了一次大的修改,做了一些优化,去了一些Bug示例: http://www.mkcoolware.com/源码: http://files.cnblogs.com/mikesoft/mkcoolupload.rar上传...
    我下载了这个组件后做了一些修改并应用了ajax技术,你们可以去

    今天又做了一次大的修改,做了一些优化,去了一些Bug
    示例:   http://www.mkcoolware.com/

    源码:  http://files.cnblogs.com/mikesoft/mkcoolupload.rar

    上传界面l

    上传界面2

    上传界面3

    wolf800@163.com
    qq:174523323  

    转载于:https://www.cnblogs.com/mikesoft/archive/2006/09/06/496768.html

    展开全文
  • JS截屏控件

    热门讨论 2012-03-21 21:06:03
    最新版本的截屏控件极大的优化了图片数据传输的效率,可以帮助用户节省约40%的上传时间。 相信新颖网络WEB截屏控件能够帮助您赢得市场。 产品特点如下: 1. 基于标准HTTP协议。 2. 支持Jpg图片格式。 3. 一流的用户...
  • 一:在QQ、TT浏览器中,uploadify上传控件不能正常工作,显示出了上传进度条,但是进度不走。解决办法如下,在前台初始化uploadify控件时,‘uploader’属性需要加随机数,让uploadify.swf文件重新下载到IE临时...

    一:在QQ、TT浏览器中,uploadify上传控件不能正常工作,显示出了上传进度条,但是进度不走。解决办法如下,在前台初始化uploadify控件时,‘uploader’属性需要加随机数,让uploadify.swf文件重新下载到IE临时文件夹。在js中我加入了时间戳:'uploader''../js/jquery.uploadify-v2.1.4/uploadify.swf?t=' + new Date().getTime()

     

    二:解决在FireFox中不工作,需要做如下4步修改:

    1、Global.asax文件中,实现Application_BeginRequest函数:

     

    void Application_BeginRequest(object sender, EventArgs e) 
        {
            
    try
            {
                
    string session_param_name = "ASPSESSID";
                
    string session_cookie_name = "ASP.NET_SessionId"
                
    if (HttpContext.Current.Request.Form[session_param_name] != null)
                {
                    updatecookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]);
                }
                
    else if (HttpContext.Current.Request.QueryString[session_param_name] != null)
                {
                    updatecookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]);
                }
            }
            
    catch
            {
            }

            
    //此处是身份验证
            try
            {
                
    string auth_param_name = "AUTHID"
                
    string auth_cookie_name = FormsAuthentication.FormsCookieName;
                
    if (HttpContext.Current.Request.Form[auth_param_name] != null)
                {
                    updatecookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]);
                }
                
    else if (HttpContext.Current.Request.QueryString[auth_param_name] != null)
                {
                    updatecookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]);
                }
            }
            
    catch { }

     } 

        

     

    2、前台js修改,注意红色代码:

     1 <script type="text/javascript">
     2         function pageLoad() {
     3             var auth = $("#<%=hfAuth.ClientID %>").val();
     4             var AspSessID = $("#<%=hfAspSessID.ClientID %>").val();
     5             $("#uploadify").uploadify({
     6                 'uploader''../js/jquery.uploadify-v2.1.4/uploadify.swf?t=' + new Date().getTime(),
     7                 'script''../JQueryUploadHandler.ashx?type=logo',
     8                 'cancelImg''../js/jquery.uploadify-v2.1.4/cancel.png',
     9                 'folder''../images/UploadFile',
    10                 'queueID''fileQueueImg',
    11                 'auto'true,
    12                 'multi'false,
    13                 'height'22,
    14                 'buttonImg''../images/file_select.png',
    15                 'fileDesc''图片文件',
    16                 'fileExt''*.gif;*.jpg;*.jpeg;*.png',
    17                 'removeCompleted'true,
    18                 'simUploadLimit''1',
    19                 scriptData: { ASPSESSID: AspSessID, AUTHID: auth },
    20                 onComplete: function(event, queueID, fileObj, response, data) {
    21                 alert("文件:" + fileObj.name + " 上传成功");
    22                 },
    23                 onError: function(event, queueID, fileObj) {
    24                     alert("文件:" + fileObj.name + " 上传失败");
    25                 }
    26             });
    27            
    28         }

    29 </script>  


     

    3、前台页面加入两个隐藏控件:

    1 <asp:HiddenField ID="hfAuth" runat="server" />

    2 <asp:HiddenField ID="hfAspSessID" runat="server" /> 


     

    4、后台pageload函数给两个隐藏控件赋值 :

    1 if (!IsPostBack)
    2         {
    3             this.hfAuth.Value = Request.Cookies[FormsAuthentication.FormsCookieName] == null ?
    4                 string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value;
    5             this.hfAspSessID.Value = Session.SessionID;

     

     三:解决uploadify控件在updatepanel中不工作,需要每次updatepanel更新时,重新初始化uploadify控件,因此将初始化代码写到function pageLoad()的js函数中,并且后台pageload中加入如下代码,该行代码不能放入if (!IsPostBack)条件判定内部。

     

    protected void Page_Load(object sender, EventArgs e)
    {
            
    this.Page.RegisterClientScriptBlock("uploadStyle""<script>pageLoad()</script>");

     

     

     

    转载于:https://www.cnblogs.com/Teddy/archive/2011/06/14/uploadifyIssue.html

    展开全文
  • 转载地址:https://mp.weixin.qq.com/s/OHzXxfcBaf5RNT4dA38LCQ 1. Form简介 Form(中文译为表单)[1],是HTML标记语言中的重要语法元素。一个Form不仅包含正常的文本内容、标记等,还包含被称为控件的特殊元素。...

    转载地址:https://mp.weixin.qq.com/s/OHzXxfcBaf5RNT4dA38LCQ

    1. Form简介

    Form(中文译为表单)[1],是HTML标记语言中的重要语法元素。一个Form不仅包含正常的文本内容、标记等,还包含被称为控件的特殊元素。用户通常通过修改控件(比如:输入文本、选择菜单项等)来“完成”表单,然后将表单数据以HTTP Get或Post请求的形式提交(submit)给Web服务器。

    很多初学者总是混淆HTML和HTTP。其实,http通常作为html传输的承载体,打个比方,html就像乘客,http就像出租车,将乘客从一个地方运输到另外一个地方。但显然http这辆出租车可不仅仅只拉html这一个乘客,很多格式均可作为http这辆出租车的乘客,比如json(over http)、xml(over http)。

    在一个HTML文档中,一个表单的标准格式如下:

    <form action="http://localhost:8080/repositories" method="get">
       <input type="text" name="language" value="go" />
       <input type="text" name="since" value="monthly" />
       <input type="submit" />               
    </form> 
    

    这样的一个Form被加载到浏览器中后会呈现为一个表单的样式,当在两个文本框中分别输入文本(或以默认的文本作为输入)后,点击“提交(submit)”,浏览器会向http://localhost:8080发出一个HTTP请求,由于Form的method属性为get,因此该HTTP请求会将表单的输入文本作为查询字符串参数(Query String Parameter,在这里即是?language=go&since=monthly)。服务器端处理完该请求后,会返回一个HTTP承载的应答,该应答被浏览器接收后会按特定样式呈现在浏览器窗口中。上述这个过程可以用总结为下面这幅示意图:

    图片

     

    Form中的method也可以使用post,就像下面这样:

    <form action="http://localhost:8080/repositories" method="post">
       <input type="text" name="language" value="go" />
       <input type="text" name="since" value="monthly" />
       <input type="submit" />
    </form>
    

    改为post的Form表单在点击提交后发出的http请求与method=get时的请求有何不同呢?不同之处就在于在method=post的情况下,表单的参数不会再以查询字符串参数的形式放在请求的URL中,而是会被写入HTTP的BODY中。我们也将这一过程用一幅示意图的形式总结一下:

    图片

     

    由于表单参数被放置在HTTP Body中传输(body中的数据为:language=go&since=monthly),因此在该HTTP请求的headers中我们会发现新增一个header字段:Content-Type,在这里例子中,它的值为application/x-www-form-urlencoded。我们可以在Form中使用enctype属性改变Form传输数据的内容编码类型,该属性的默认值就是application/x-www-form-urlencoded(即key1=value1&key2=value2&...的形式)。enctype的其它可选值还包括:

    • text/plain

    • multipart/form-data

    采用method=get的Form的表单参数以查询字符串参数的形式放入http请求,这使得其应用场景相对局限,比如:

    • 当参数值很多,参数值很长时,可能会超出URL最大长度限制;

    • 传递敏感数据时,参数值以明文放在HTTP请求头是不安全的;

    • 无法胜任传递二进制数据(比如一个文件内容)的情形。

    因此,在面对上述这些情形时,method=post的表单更有优势。当enctype为不同值时,method=post的表单在http Body中传输的数据形式如下图:

    图片

     

    我们看到:enctype=application/x-www-urlencoded时,Body中的数据呈现为key1=value1&key2=value2&...的形式,好似URL的查询字符串参数的组合呈现形式;当enctype=text/plain时,这种编码格式也称为raw,即将数据内容原封不动的放入Body中传输,保持数据的原先的编码方式(通常为utf-8);而当enctype=multipart/form-data时,HTTP Body中的数据以多段(part)的形式呈现,段与段之间使用指定的随机字符串分隔,该随机字符串也会随着HTTP Post请求一并传给服务端(放在Header中的Content-Type的值中,与multipart/form-data使用分号相隔),如:

    Content-Type: multipart/form-data; boundary=--------------------------399501358433894470769897
    

    我们来看一个稍微复杂些的enctype=multipart/form-data的例子的示意图:

    图片

     

    我们用Postman模拟了一个包含5个分段(part)的Post请求,其中包含两个文本分段(text)和三个文件分段,并且这三个文件是不同格式的文件,分别是txt,png和json。针对文件分段,Postman使用每个分段中的Content-Type来指明这个分段的数据内容类型。当服务端接收到这些数据时,根据分段Content-Type的指示,便可以有针对性的对分段数据进行解析了。文件分段的默认Content-Type为text/plain;对于无法识别的文件类型(比如:没有扩展名),文件分段的Content-Type通常会设置为application/octet-stream

    通过Form上传文件是RFC1867规范[2]赋予html的一种能力,并且该能力已被证明非常有用,并被广泛使用,甚至我们可以直接将multipart/form-data作为HTTP Post body的一种数据承载协议在两个端之间传输文件数据。

    2. 支持以multipart/form-data格式上传文件的Go服务器

    http.Request提供了ParseMultipartForm的方法对以multipart/form-data格式传输的数据进行解析,解析即是将数据映射为Request结构的MultipartForm字段的过程:

    // $GOROOT/src/net/http/request.go
    
    type Request struct {
        ... ...
        // MultipartForm is the parsed multipart form, including file uploads.
        // This field is only available after ParseMultipartForm is called.
        // The HTTP client ignores MultipartForm and uses Body instead.
        MultipartForm *multipart.Form
        ... ...
    }
    

    multipart.Form代表了一个解析后的multipart/form-data的Body,其结构如下:

    // $GOROOT/src/mime/multipart/formdata.go
    
    // Form is a parsed multipart form.
    // Its File parts are stored either in memory or on disk,
    // and are accessible via the *FileHeader's Open method.
    // Its Value parts are stored as strings.
    // Both are keyed by field name.
    type Form struct {
            Value map[string][]string
            File  map[string][]*FileHeader
    }
    

    我们看到这个Form结构由两个map组成,一个map中存放了所有的value part(就像前面的name、age),另外一个map存放了所有的file part(就像前面的part1.txt、part2.png和part3.json)。value part集合没什么可说的,map的key就是每个值分段中的"name";我们的重点在file part上。每个file part对应一组FileHeader,FileHeader的结构如下:

    // $GOROOT/src/mime/multipart/formdata.go
    type FileHeader struct {
            Filename string
            Header   textproto.MIMEHeader
            Size     int64
    
            content []byte
            tmpfile string
    }
    

    每个file part的FileHeader包含五个字段:

    • Filename - 上传文件的原始文件名

    • Size - 上传文件的大小(单位:字节)

    • content - 内存中存储的上传文件的(部分或全部)数据内容

    • tmpfile - 在服务器本地的临时文件中存储的部分上传文件的数据内容(如果上传的文件大小大于传给ParseMultipartForm的参数maxMemory,剩余部分存储在临时文件中)

    • Header - file part的header内容,它亦是一个map,其结构如下:

    // $GOROOT/src/net/textproto/header.go
    
    // A MIMEHeader represents a MIME-style header mapping
    // keys to sets of values.
    type MIMEHeader map[string][]string
    

    我们可以将ParseMultipartForm方法实现的数据映射过程表述为下面这张示意图,这样看起来更为直观:

    图片

     

    有了上述对通过multipart/form-data格式上传文件的原理的拆解,我们就可以很容易地利用Go http包实现一个简单的支持以multipart/form-data格式上传文件的Go服务器:

    // github.com/bigwhite/experiments/multipart-formdata/server/file_server1.go
    package main
    
    import (
     "fmt"
     "io"
     "net/http"
     "os"
    )
    
    const uploadPath = "./upload"
    
    func handleUploadFile(w http.ResponseWriter, r *http.Request) {
     r.ParseMultipartForm(100)
     mForm := r.MultipartForm
    
     for k, _ := range mForm.File {
      // k is the key of file part
      file, fileHeader, err := r.FormFile(k)
      if err != nil {
       fmt.Println("inovke FormFile error:", err)
       return
      }
      defer file.Close()
      fmt.Printf("the uploaded file: name[%s], size[%d], header[%#v]\n",
       fileHeader.Filename, fileHeader.Size, fileHeader.Header)
    
      // store uploaded file into local path
      localFileName := uploadPath + "/" + fileHeader.Filename
      out, err := os.Create(localFileName)
      if err != nil {
       fmt.Printf("failed to open the file %s for writing", localFileName)
       return
      }
      defer out.Close()
      _, err = io.Copy(out, file)
      if err != nil {
       fmt.Printf("copy file err:%s\n", err)
       return
      }
      fmt.Printf("file %s uploaded ok\n", fileHeader.Filename)
     }
    }
    
    func main() {
     http.HandleFunc("/upload", handleUploadFile)
     http.ListenAndServe(":8080", nil)
    }
    

    我们可以用Postman或下面curl命令向上述文件服务器同时上传两个文件part1.txt和part3.json:

    curl --location --request POST ':8080/upload' \
    --form 'name="tony bai"' \
    --form 'age="23"' \
    --form 'file1=@"/your_local_path/part1.txt"' \
    --form 'file3=@"/your_local_path/part3.json"'
    

    文件上传服务器的运行输出日志如下:

    $go run file_server1.go
    the uploaded file: name[part3.json], size[130], header[textproto.MIMEHeader{"Content-Disposition":[]string{"form-data; name=\"file3\"; filename=\"part3.json\""}, "Content-Type":[]string{"application/json"}}]
    file part3.json uploaded ok
    the uploaded file: name[part1.txt], size[15], header[textproto.MIMEHeader{"Content-Disposition":[]string{"form-data; name=\"file1\"; filename=\"part1.txt\""}, "Content-Type":[]string{"text/plain"}}]
    file part1.txt uploaded ok
    

    之后我们可以看到:文件上传服务器成功地将接收到的part1.txt和part3.json存储到了当前路径下的upload目录中了!

    3. 支持以multipart/form-data格式上传文件的Go客户端

    前面进行文件上传的客户端要么是浏览器,要么是Postman,要么是curl,如果我们自己构要造一个支持以multipart/form-data格式上传文件的客户端,应该如何做呢?我们需要按照multipart/form-data的格式构造HTTP请求的包体(Body),还好通过Go标准库提供的mime/multipart包,我们可以很容易地构建出满足要求的包体:

    // github.com/bigwhite/experiments/multipart-formdata/client/client1.go
    
    ... ...
    var (
     filePath string
     addr     string
    )
    
    func init() {
     flag.StringVar(&filePath, "file", "", "the file to upload")
     flag.StringVar(&addr, "addr", "localhost:8080", "the addr of file server")
     flag.Parse()
    }
    
    func main() {
     if filePath == "" {
      fmt.Println("file must not be empty")
      return
     }
    
     err := doUpload(addr, filePath)
     if err != nil {
      fmt.Printf("upload file [%s] error: %s", filePath, err)
      return
     }
     fmt.Printf("upload file [%s] ok\n", filePath)
    }
    
    func createReqBody(filePath string) (string, io.Reader, error) {
     var err error
    
     buf := new(bytes.Buffer)
     bw := multipart.NewWriter(buf) // body writer
    
     f, err := os.Open(filePath)
     if err != nil {
      return "", nil, err
     }
     defer f.Close()
    
     // text part1
     p1w, _ := bw.CreateFormField("name")
     p1w.Write([]byte("Tony Bai"))
    
     // text part2
     p2w, _ := bw.CreateFormField("age")
     p2w.Write([]byte("15"))
    
     // file part1
     _, fileName := filepath.Split(filePath)
     fw1, _ := bw.CreateFormFile("file1", fileName)
     io.Copy(fw1, f)
    
     bw.Close() //write the tail boundry
     return bw.FormDataContentType(), buf, nil
    }
    
    func doUpload(addr, filePath string) error {
     // create body
     contType, reader, err := createReqBody(filePath)
     if err != nil {
      return err
     }
    
     url := fmt.Sprintf("http://%s/upload", addr)
     req, err := http.NewRequest("POST", url, reader)
    
     // add headers
     req.Header.Add("Content-Type", contType)
    
     client := &http.Client{}
     resp, err := client.Do(req)
     if err != nil {
      fmt.Println("request send error:", err)
      return err
     }
     resp.Body.Close()
     return nil
    }
    

    显然上面这个client端的代码的核心是createReqBody函数:

    • 该client在body中创建了三个分段,前两个分段仅仅是我为了演示如何创建text part而故意加入的,真正的上传文件客户端是不需要创建这两个分段(part)的;

    • createReqBody使用bytes.Buffer作为http body的临时存储;

    • 构建完body内容后,不要忘记调用multipart.Writer的Close方法以写入结尾的boundary标记。

    我们使用这个客户端向前面的支持以multipart/form-data格式上传文件的服务器上传一个文件:

    // 客户端
    $go run client1.go -file hello.txt
    upload file [hello.txt] ok
    
    // 服务端
    $go run file_server1.go
    
    http request: http.Request{Method:"POST", URL:(*url.URL)(0xc00016e100), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Accept-Encoding":[]string{"gzip"}, "Content-Length":[]string{"492"}, "Content-Type":[]string{"multipart/form-data; boundary=b55090594eaa1aaac1abad1d89a77ae689130d79d6f66af82590036bd8ba"}, "User-Agent":[]string{"Go-http-client/1.1"}}, Body:(*http.body)(0xc000146380), GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:492, TransferEncoding:[]string(nil), Close:false, Host:"localhost:8080", Form:url.Values{"age":[]string{"15"}, "name":[]string{"Tony Bai"}}, PostForm:url.Values{"age":[]string{"15"}, "name":[]string{"Tony Bai"}}, MultipartForm:(*multipart.Form)(0xc000110d50), Trailer:http.Header(nil), RemoteAddr:"[::1]:58569", RequestURI:"/upload", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:(*context.cancelCtx)(0xc0001463c0)}
    the uploaded file: name[hello.txt], size[15], header[textproto.MIMEHeader{"Content-Disposition":[]string{"form-data; name=\"file1\"; filename=\"hello.txt\""}, "Content-Type":[]string{"application/octet-stream"}}]
    file hello.txt uploaded ok
    

    我们看到hello.txt这个文本文件被成功上传!

    4. 自定义file分段中的header

    从上面file_server1的输出来看,client1这个客户端上传文件时在file分段(part)中设置的Content-Type为默认的application/octet-stream。有时候,服务端可能会需要根据这个Content-Type做分类处理,需要客户端给出准确的值。上面的client1实现中,我们使用了multipart.Writer.CreateFormFile这个方法来创建file part:

    // file part1
    _, fileName := filepath.Split(filePath)
    fw1, _ := bw.CreateFormFile("file1", fileName)
    io.Copy(fw1, f)
    

    下面是标准库中CreateFormFile方法的实现代码:

    // $GOROOT/mime/multipart/writer.go
    func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {
            h := make(textproto.MIMEHeader)
            h.Set("Content-Disposition",
                    fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
                            escapeQuotes(fieldname), escapeQuotes(filename)))
            h.Set("Content-Type", "application/octet-stream")
            return w.CreatePart(h)
    }
    

    我们看到无论待上传的文件是什么类型,CreateFormFile均将Content-Type置为application/octet-stream这一默认值。如果我们要自定义file part中Header字段Content-Type的值,我们就不能直接使用CreateFormFile,不过我们可以参考其实现:

    // github.com/bigwhite/experiments/multipart-formdata/client/client2.go
    
    var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
    
    func escapeQuotes(s string) string {
     return quoteEscaper.Replace(s)
    }
    
    func createReqBody(filePath string) (string, io.Reader, error) {
     var err error
    
     buf := new(bytes.Buffer)
     bw := multipart.NewWriter(buf) // body writer
    
     f, err := os.Open(filePath)
     if err != nil {
      return "", nil, err
     }
     defer f.Close()
    
     // text part1
     p1w, _ := bw.CreateFormField("name")
     p1w.Write([]byte("Tony Bai"))
    
     // text part2
     p2w, _ := bw.CreateFormField("age")
     p2w.Write([]byte("15"))
    
     // file part1
     _, fileName := filepath.Split(filePath)
     h := make(textproto.MIMEHeader)
     h.Set("Content-Disposition",
      fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
       escapeQuotes("file1"), escapeQuotes(fileName)))
     h.Set("Content-Type", "text/plain")
     fw1, _ := bw.CreatePart(h)
     io.Copy(fw1, f)
    
     bw.Close() //write the tail boundry
     return bw.FormDataContentType(), buf, nil
    }
    

    我们通过textproto.MIMEHeader实例来自定义file part的header部分,然后基于该实例调用CreatePart创建file part,之后将hello.txt的文件内容写到该part的header后面。

    我们运行client2来上传hello.txt文件,在file_server侧,我们就能看到如下日志:

    the uploaded file: name[hello.txt], size[15], header[textproto.MIMEHeader{"Content-Disposition":[]string{"form-data; name=\"file1\"; filename=\"hello.txt\""}, "Content-Type":[]string{"text/plain"}}]
    file hello.txt uploaded ok
    

    我们看到file part的Content-Type的值已经变为我们设定的text/plain了。

    5. 解决上传大文件的问题

    在上面的客户端中存在一个问题,那就是我们在构建http body的时候,使用了一个bytes.Buffer加载了待上传文件的所有内容,这样一来,如果待上传的文件很大的话,内存空间消耗势必过大。那么如何将每次上传内存文件时对内存的使用限制在一个适当的范围,或者说上传文件所消耗的内存空间不因待传文件的变大而变大呢?我们来看下面的这个解决方案:

    // github.com/bigwhite/experiments/multipart-formdata/client/client3.go
    ... ...
    func createReqBody(filePath string) (string, io.Reader, error) {
     var err error
     pr, pw := io.Pipe()
     bw := multipart.NewWriter(pw) // body writer
     f, err := os.Open(filePath)
     if err != nil {
      return "", nil, err
     }
    
     go func() {
      defer f.Close()
      // text part1
      p1w, _ := bw.CreateFormField("name")
      p1w.Write([]byte("Tony Bai"))
    
      // text part2
      p2w, _ := bw.CreateFormField("age")
      p2w.Write([]byte("15"))
    
      // file part1
      _, fileName := filepath.Split(filePath)
      h := make(textproto.MIMEHeader)
      h.Set("Content-Disposition",
       fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
        escapeQuotes("file1"), escapeQuotes(fileName)))
      h.Set("Content-Type", "application/pdf")
      fw1, _ := bw.CreatePart(h)
      cnt, _ := io.Copy(fw1, f)
      log.Printf("copy %d bytes from file %s in total\n", cnt, fileName)
      bw.Close() //write the tail boundry
      pw.Close()
     }()
     return bw.FormDataContentType(), pr, nil
    }
    
    func doUpload(addr, filePath string) error {
     // create body
     contType, reader, err := createReqBody(filePath)
     if err != nil {
      return err
     }
    
     log.Printf("createReqBody ok\n")
     url := fmt.Sprintf("http://%s/upload", addr)
     req, err := http.NewRequest("POST", url, reader)
    
     //add headers
     req.Header.Add("Content-Type", contType)
    
     client := &http.Client{}
     log.Printf("upload %s...\n", filePath)
     resp, err := client.Do(req)
     if err != nil {
      fmt.Println("request send error:", err)
      return err
     }
     resp.Body.Close()
     log.Printf("upload %s ok\n", filePath)
     return nil
    }
    

    在这个方案中,我们通过io.Pipe函数创建了一个读写管道,其写端作为io.Writer实例传给multipart.NewWriter,读端返回给调用者,用于构建http request时使用。io.Pipe基于channel实现,其内部不维护任何内存缓存:

    // $GOROOT/src/io/pipe.go
    func Pipe() (*PipeReader, *PipeWriter) {
            p := &pipe{
                    wrCh: make(chan []byte),
                    rdCh: make(chan int),
                    done: make(chan struct{}),
            }
            return &PipeReader{p}, &PipeWriter{p}
    }
    

    通过Pipe返回的读端读取管道中数据时,如果尚未有数据写入管道,那么读端会像读取channel那样阻塞在那里。由于http request在被发送时(client.Do(req))才会真正基于构建req时传入的reader对Body数据进行读取,因此client会阻塞在对管道的read上。显然我们不能将读写两端的操作放在一个goroutine中,那样会因所有goroutine都挂起而导致panic。在上面的client3.go代码中,函数createReqBody内部创建了一个新goroutine,将真正构建multipart/form-data body的工作放在了新goroutine中。新goroutine最终会将待上传文件的数据通过管道写端写入管道:

    cnt, _ := io.Copy(fw1, f)
    

    而这些数据也会被client读取并通过网络连接传输出去。io.Copy的实现如下:

    // $GOROOT/src/io/io.go
    func Copy(dst Writer, src Reader) (written int64, err error) {
            return copyBuffer(dst, src, nil)
    }
    

    io.copyBuffer内部维护了一个默认32k的小buffer,它每次从src尝试最大读取32k的数据,并写入到dst中,直到读完为止。这样无论待上传的文件有多大,我们实际上每次上传所分配的内存仅有32k。

    下面就是我们用client3.go上传一个大小为252M的文件的日志:

    $go run client3.go -file /Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf
    2021/01/10 12:56:45 createReqBody ok
    2021/01/10 12:56:45 upload /Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf...
    2021/01/10 12:56:46 copy 264517032 bytes from file ICME-2019-Tutorial-final.pdf in total
    2021/01/10 12:56:46 upload /Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf ok
    upload file [/Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf] ok
    
    $go run file_server1.go
    http request: http.Request{Method:"POST", URL:(*url.URL)(0xc000078200), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Accept-Encoding":[]string{"gzip"}, "Content-Type":[]string{"multipart/form-data; boundary=4470ba3867218f1130878713da88b5bd79f33dfbed65566e4fd76a1ae58d"}, "User-Agent":[]string{"Go-http-client/1.1"}}, Body:(*http.body)(0xc000026240), GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:-1, TransferEncoding:[]string{"chunked"}, Close:false, Host:"localhost:8080", Form:url.Values{"age":[]string{"15"}, "name":[]string{"Tony Bai"}}, PostForm:url.Values{"age":[]string{"15"}, "name":[]string{"Tony Bai"}}, MultipartForm:(*multipart.Form)(0xc0000122a0), Trailer:http.Header(nil), RemoteAddr:"[::1]:54899", RequestURI:"/upload", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:(*context.cancelCtx)(0xc000026280)}
    the uploaded file: name[ICME-2019-Tutorial-final.pdf], size[264517032], header[textproto.MIMEHeader{"Content-Disposition":[]string{"form-data; name=\"file1\"; filename=\"ICME-2019-Tutorial-final.pdf\""}, "Content-Type":[]string{"application/pdf"}}]
    file ICME-2019-Tutorial-final.pdf uploaded ok
    
    $ls -l upload
    -rw-r--r--  1 tonybai  staff  264517032  1 14 12:56 ICME-2019-Tutorial-final.pdf
    

    如果你觉得32k仍然很大,每次上传要使用更小的buffer,你可以用io.CopyBuffer替代io.Copy:

    // github.com/bigwhite/experiments/multipart-formdata/client/client4.go
    
    func createReqBody(filePath string) (string, io.Reader, error) {
     var err error
     pr, pw := io.Pipe()
     bw := multipart.NewWriter(pw) // body writer
     f, err := os.Open(filePath)
     if err != nil {
      return "", nil, err
     }
    
     go func() {
      defer f.Close()
      // text part1
      p1w, _ := bw.CreateFormField("name")
      p1w.Write([]byte("Tony Bai"))
    
      // text part2
      p2w, _ := bw.CreateFormField("age")
      p2w.Write([]byte("15"))
    
      // file part1
      _, fileName := filepath.Split(filePath)
      h := make(textproto.MIMEHeader)
      h.Set("Content-Disposition",
       fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
        escapeQuotes("file1"), escapeQuotes(fileName)))
      h.Set("Content-Type", "application/pdf")
      fw1, _ := bw.CreatePart(h)
      var buf = make([]byte, 1024)
      cnt, _ := io.CopyBuffer(fw1, f, buf)
      log.Printf("copy %d bytes from file %s in total\n", cnt, fileName)
      bw.Close() //write the tail boundry
      pw.Close()
     }()
     return bw.FormDataContentType(), pr, nil
    }
    

    运行这个client4:

    $go run client4.go -file /Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf
    2021/01/10 13:39:06 createReqBody ok
    2021/01/10 13:39:06 upload /Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf...
    2021/01/10 13:39:09 copy 264517032 bytes from file ICME-2019-Tutorial-final.pdf in total
    2021/01/10 13:39:09 upload /Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf ok
    upload file [/Users/tonybai/Downloads/ICME-2019-Tutorial-final.pdf] ok
    

    你会看到虽然上传成功了,但由于每次read仅能读1k数据,对于大文件来说,其上传的时间消耗增加了不少。

    展开全文
  • ///FileDownload()文件下载 调用方法如 FileDownload(Response,Server,文件虚拟路径) ///FileTxtWrite()写入TXT文本 给出要创建Txt 文本的地址 ///FileTxtReader()读取TXT文本 Txt 文本的地址 返回一个数组 ...
  • 现在很多下载客户端程序都需要设定自己头像的功能,而设定头像一般有两种方式:使用摄像头自拍头像,或者选择一个图片的某部分区域作为自己的头像。 一.相关技术  若要实现上述的自拍头像和上传头像的功能,...

     现在很多下载客户端程序都需要设定自己头像的功能,而设定头像一般有两种方式:使用摄像头自拍头像,或者选择一个图片的某部分区域作为自己的头像。

    一.相关技术

      若要实现上述的自拍头像和上传头像的功能,会碰到以下要解决的问题:

    (1)调用摄像头,捕获摄像头采集的视频,并将采集的视频绘制到UI上。

    (2)从图片文件读取Image,并显示在控件上(这个相当easy)。

    (3)在显示的视频或图片上,能够拖动一个正方形,以选择指定部分的区域作为自己的头像。

    (4)从视频中截获一帧保存为图片。

    (5)从图片中截取某个区域作为自己的头像。

      为了解决这些问题,就需要涉及到的技术有DirectX Show、GDI+、drawdib(位图绘制)、图像截取等。

    二.Demo实现

      当然这篇文章不是要告诉大家这些技术的详细细节,相关的资料网上有很多,如果需要从头到尾自己实现,可以从了解这些技术入手。在这里,我将傲瑞通OrayTalk)中的设定头像的功能拆分出来做成一个demo,供大家参考和使用,避免大家浪费时间重复发明轮子。我们先看看demo的运行效果。

      自拍头像:

          

      上传头像:

          

      在demo中,点击窗体上的确定按钮,就会自动将所选择区域的图像保存为自己的头像了。这是怎么做到的了?实际上,我们是使用了OMCS提供的两个控件:HeadImagePanel和ImagePartSelecter。

    1.HeadImagePanel 控件

      先看看HeadImagePanel控件的定义吧:

    复制代码
        public class HeadImagePanel : UserControl
        {  
            // 当选择的头像区域发生改变时,会触发此事件。参数为头像位图。
            public event CbGeneric<Bitmap> HeadImageSelected;
    
            // 获取结果头像。
            public Bitmap GetHeadImage();
    
            // 初始化摄像头,并启动它。             
         //   cameraDeviceIndex: 摄像头的索引
            //   cameraSize: 摄像头采集分辨率
            //   outputImageLen: 输出的正方形头像的边长
            public void Start(int cameraDeviceIndex, Size cameraSize, int outputImageLen);
    
           // 停止摄像头。
            public void Stop();
        }
    复制代码

    (1)将HeadImagePanel拖到窗体上,然后调用其Start方法,它就会自动启动摄像头,并将捕捉的视频绘制带该控件的表面上,而且,同时会在视频的上面绘制蓝边的正方形,我们可以通过拖动或改变这个正方形的大小,来指定选择的区域。

    (2)当区域指定好后,可以调用其GetHeadImage方法,其就会返回最终的结果图像(即指定区域内的视频图像)。

    (3)使用完毕后,调用HeadImagePanel的Stop方法以释放摄像头及相关的其它资源。

    (4)要特别注意的是,请将HeadImagePanel控件的Size设置为与摄像头采集分辨率一样的大小。否则,结果图像将是有偏差的。

    2.ImagePartSelecter 控件

      图像区域选择控件ImagePartSelecter的定义如下: 

    复制代码
        public class ImagePartSelecter : UserControl
        {       
           // 当选择的区域发生改变时,会触发此事件。事件参数为原始图片的选择区域截图。
            public event CbGeneric<Bitmap> ImagePartSelected;        
      
         // 获取结果图片(原始图片的选择区域截图)。
            public Bitmap GetResultImage();
    
           // 初始化。               
           // outputImgLen: 最终要输出的正方形图片的边长。
            public void Initialize(int outputImgLen);
    
           // 指定要被选取的图片。
            public void SetSourceImage(Image image);
        }
    复制代码

    (1)将ImagePartSelecter控件拖到窗体上,调用Initialize方法初始化。

    (2)调用SetSourceImage方法设置原始的头像图片,这样,图片会显示在控件的表面,而且ImagePartSelecter会在图像的上面绘制蓝边的正方形,我们可以通过拖动或改变这个正方形的大小,来指定选择的区域。

    (3)当区域指定好后,可以调用其GetResultImage方法,其就会返回最终的结果图像(即指定区域内的图像)。

    (4)与HeadImagePanel控件不一样的是,不需要将ImagePartSelecter控件的Size设置为与图片一样的大小,ImagePartSelecter内部会自动缩放并适应。 

    三.源码下载

       自拍头像Demo(源码)

       源码就不贴出来了,大家下载自己看吧:)

      

       如果觉得这篇文章对你有帮助,请顶一下,并粉我啊,嘿嘿

     

    展开全文
  • VC普通控件操作

    2013-05-02 13:41:16
     实例91 FTP上传下载   实例92 网络聊天:WINSOCK-TCP   实例93 广播信息:WINSOCK-UDP   实例94 电话拨号上网  第10章 数学算法   实例95 进制转换   实例96 随机选号   实例97 统计中英文...
  • 现在很多下载客户端程序都需要设定自己头像的功能,而设定头像一般有两种方式:使用摄像头自拍头像,或者选择一个图片的某部分区域作为自己的头像。 一.相关技术  若要实现上述的自拍头像和上传头像的功能,会...
  • FolderBrowserDialogScrollToSelectdPath wpf 或者 winform 的选择文件夹路径...另外吐槽一下csdn的下载积分规则,我上传的资源都希望是0积分共享,看重任何资源的,请往邮箱 939533837@qq.com 发信息,看见后免费分享
  • 咖啡智能报表控件 2.0[下载地址] 咖啡智能报表组件是一个类似Excel风格的报表组件 1、操作风格与EXCEL类似,是一款表格型报表组件,功能强大、操作简单 2、灵活多样性的单元格属性 合并、拆分、对齐方式、背景、...
  • 今天早上打开Xmind软件发现做了一天的Jmeter总结没了,差点...有需要的同学可以去下载,没有下载币的可以直接联系我QQ:1570310730。另外我也是个初学者,如果总结的有不对的地方,劳烦大佬指点。谢谢。 补充: ...
  • 9种风格的进度条。包括标准进度条、3种仿XP风格、仿手机QQ、仿360安全卫士、仿Windows 7(即...相比许多下载了别人复制一分让体积变大然后又上传上去的进度条来说,该进度条可以算是目前最完整的进度条了。适用与C# 2.0
  • ///FileDownload()文件下载 调用方法如 FileDownload(Response,Server,文件虚拟路径) ///FileTxtWrite()写入TXT文本 给出要创建Txt 文本的地址 ///FileTxtReader()读取TXT文本 Txt 文本的地址 返回一个数组 每...
  • php批量上传图片代码

    热门讨论 2012-12-03 14:13:17
    在最新版的图片上传控件中采用了全新的网络数据传输模块,新的模块全面优化了网络层的数据处理代码,同时在接收服务器返回的数据代码中采用精确识别的方式使数据处理效率更高。这些改进使图片上传控件具有了闪电般的...
  • web网页批量上传图片代码

    热门讨论 2012-12-03 14:11:37
    在最新版的图片上传控件中采用了全新的网络数据传输模块,新的模块全面优化了网络层的数据处理代码,同时在接收服务器返回的数据代码中采用精确识别的方式使数据处理效率更高。这些改进使图片上传控件具有了闪电般的...
  • 因为XCL_Charts 是个第三方库所以需要在 Is Library里面勾选中这个项目,因为只可以上传一个文件的原因XCL_Charts需要你去百度自行下载, 如有不懂可以加qq咨询 554828663
  • 控件特点如下: 1. 支持2G文件断点续传功能。 2. 支持文件MD5验证功能。 3. 支持文件及文件夹拖拽上传功能。 4. 支持文件批量上传。 5. 支持文件夹上传。 6. 基于标准HTTP协议。 7. 免费提供JavaScript SDK...
  • 1、首先在这个网站下载控件包,并引入网站。 http://fex.baidu.com/webuploader/?qq-pf-to=pcqq.c2c 根据网站说明和自己的需求取用不同的文件。 我是用了这么几个(swf css js 这三个都是要用的,就是看你选择...
  • 在写QQ邮箱自动发送邮件功能的时候,要实现上传附件功能,需要对Windows界面进行操作,但是selenium无法实现,可以使用AutoIt,利用此工具来识别Windows控件信息,如输入框、按钮等。 下面使用步骤: 1.下载AutoIT3...
  • 经过我的一些探索之路,我终于发现了我的win7电脑的...为了不让大家下载错误版本,我在我的文件里面上传了安装包,大家如果有需要自行下载下载链接:https://download.csdn.net/download/qq_37220238/10843624 2...
  • QQ交流群 : ③816531124、②769925425(满)、①284271917(满) 反馈问题: 反馈问题,请按格式发Issues 参与开源: 欢迎加入JEECG开源团队,共同进步!! Online一分钟: 1分钟快速学习 为什么选择JEECG...
  • QQ界面含图片动态分组菜单的实现[C#]源码下载:http://download.csdn.net/source/1618670源码传了两次,显示上传成功,但都没见着,那就将就着看吧,挺简单的:问题点说明:1)主要用到了Dock属性:(略) 2)SendToBack()...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 179
精华内容 71
关键字:

qq上传控件下载