精华内容
下载资源
问答
  • 很多项目中可能需要从外部实时读入文件,但不是上传,对于这种该怎么实现呢。 日前,笔者也遇到一个类似的问题。就是项目中有一个文本框和导入按钮,要求点击按钮时可以导入excel文件,然后能自动读取其中的线路号...

    很多项目中可能需要从外部实时读入文件,但不是上传,对于这种该怎么实现呢。

    日前,笔者也遇到一个类似的问题。就是项目中有一个文本框和导入按钮,要求点击按钮时可以导入excel文件,然后能自动读取其中的线路号显示到文本中。毫无意外,便开始在网上搜索JS实现相关功能的帖子,也获得了很多有用的经验。可唯一的问题是,总会出现一些困然的小问题。也是为了给以后的小伙伴省下时间,笔者在这里给大家一个较好的实现。

    不多说,先上代码:

    <html>  
     <head>  
      <title> New Document </title>
        <meta charset="utf-8">  
      <meta name="Generator" content="EditPlus">  
      <meta name="Author" content="">  
      <meta name="Keywords" content="">  
      <meta name="Description" content="">  
      <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
      <script type="text/javascript">  
        var oWB = null;
        var oXL = null;
        function loadExcel() {
               $("#upfile").click();
               //得到文件路径的值  
               var filePath = $("#upfile").val();  
               //创建操作EXCEL应用程序的实例  
               try{
                this.oXL = new ActiveXObject("Excel.Application");
                try{
                    //打开指定路径的excel文件  
                    this.oWB = this.oXL.Workbooks.open(filePath);  
                    //获取sheet数
                     var sheet = this.oWB.Worksheets.count;
                    //返回所传excel表格的sheet数供选择               
                    $("#sheet").css("display","block");
                    for(var i = 1;i <= sheet;i++){
                        var option = '<option value="'+i+'">-第'+i+'页-</option>';
                        $("#sheet").append(option);    
                    }
                }catch(e){
                    alert("请设置浏览器启用将文件上传到浏览器时包含本地路径!");
                }
                }catch(e){
                    alert("请设置浏览器允许初始化和执行未标记为可安全执行脚本的ActiveX控件!");
                }           
            }
        function readexcel(){
            var selsheet = $("#sheet").val();        
            var tempStr = [];  
                   //操纵所选sheet页(从一开始,而非零)  
               oWB.worksheets(parseInt(selsheet)).select();  
               var oSheet = oWB.ActiveSheet;            
               //使用的行数和列数  
             var rows =  oSheet.usedrange.rows.count;
             var columns = oSheet.usedrange.Columns.count;
             //查找线路号所在列
             var j = 1;
             for(j;j <= columns; j++){
                if(oSheet.Cells(1, j).value == "线路"){
                    break;
                }
             }
               try { 
                //首行首列为表头,默认不取值。
                  for (var i = 2; i <= rows; i++) { 
                      if(oSheet.Cells(i, j).value){
                          tempStr.push(oSheet.Cells(i, j).value)
                            //tempStr += oSheet.Cells(i, 3).value + "," ;
                        }
                  }
                    
               } catch(e) {  
                  $("#txtArea").val(tempStr);  
               }             
               $("#txtArea").val(tempStr);  
               //退出操作excel的实例对象  
               //oXL.Application.Quit();  
                //手动调用垃圾收集器  
               //CollectGarbage();  
        }    
      </script>  
     </head>  
      
     <body>
      <input type="text" id="txtArea" style="float:left;"/>  
      <input type="file" id="upfile" style="float:left; display:none;" />
      <select id="sheet" style="display:none; height:21px; float:left;" onchange="readexcel()">
        <option value="" selected>-请选择-</option>
      </select>  
      <input type="button" style="float:left; height:21px;" onclick="loadExcel();" value="read">  
    <br>  
     </body>  
    </html>  


     

    运行结果图:

     

     

     

    因为excel中可能有多个sheet页,因而笔者设计了一个自动加载页数并根据页数读入数据的功能,大家可以适当跟着改一下。

    另外,请读者朋友们注意,此方法需要设置浏览器启用将文件上传到浏览器时包含本地路径,以及允许或提示初始化和执行未标记为可安全执行脚本的ActiveX控件。

    转载于:https://www.cnblogs.com/Only-lovw-you/p/7412956.html

    展开全文
  • 本文地址:今天要分享的功能是一键上传excel文件,然后显示在页面中,以及将网页上的数据已excel文件的形式下载下来。使用的是Apache的POI,本文分享的实例是SSH框架完成的一个项目中的一个功能模块之一,使用Maven...

    本文地址:http://blog.csdn.net/shanglianlm/article/details/52562028

    今天要分享的功能是一键上传excel文件,然后显示在页面中,以及将网页上的数据已excel文件的形式下载下来。使用的是Apache的POI,本文分享的实例是SSH框架完成的一个项目中的一个功能模块之一,使用了Maven,所以相关的jar包都贴出了maven的相关jar坐标。因为这个项目设计了很多ssh的配置,这里本文就不在一一列出,只写了关键的代码,文末提供源码下载,希望可以帮助到有需要的开发者。
    一、POI简介
    Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“可怜的模糊实现”。
    Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解决方案(适用于Excel97-2008)。

    网址是http://poi.apache.org/,我们可以通过添加maven倚赖的方式下载,poi的坐标是:

    <dependency>  
        <groupId>org.apache.poi</groupId>  
        <artifactId>poi</artifactId>  
        <version>3.9</version>  
    </dependency>  

    二、实例准备

    页面效果如下:
    (这里的数据我是随便写的,仅作为参考数据,不是真实数据)

    这里写图片描述

    通过点击页面上的批量导入按钮,可以实现界面无刷新一次性导入写好的数据。我们先excel中准备好数据:注意的是在excel中的数字都要改为文本格式的,不能是“常规”,否则导入会失败的。

    这里写图片描述

    三、一键上传
    jsp页面代码:
    需要先导入:jquery.ocupload-1.1.2.js
    然后再页面中给你的按钮的id添加upload的方法。 (以下片段在文末项目中的位置是:/BOS/src/main/webapp/WEB-INF/pages/base/region.jsp)

    // 对批量导入添加一键上传效果   
    $('#button-import').upload({  
        name : 'upload',   
        action : '${pageContext.request.contextPath}/region_OCimport', // 表单提交路径  
        onComplete : function(response){  
            var data = eval("("+response+")");  
            $.messager.alert('信息',data.msg,'info');  
            $('#grid').datagrid('reload');  
        }  
    });  

    这个我转到的是Action中:
    这里的话我就是加了pinyin4j来将汉字转为拼音,这样的话做的就是简码了;
    在pom.xml中添加maven依赖:(以下片段在文末项目中的位置是:/BOS/pom.xml)

    <dependency>  
        <groupId>com.belerweb</groupId>  
        <artifactId>pinyin4j</artifactId>  
        <version>2.5.0</version>  
    </dependency>  

    在Action中处理:(以下片段在文末项目中的位置是:/BOS/src/main/java/cn/tf/bos/web/action/bc/RegionAction.java)

    //接收上传的数据  
        public String OCimport() throws IOException{  
    
            // 1、 工作薄对象  
            HSSFWorkbook hssfWorkbook = new HSSFWorkbook(new FileInputStream(upload));  
            // 解析工作薄  
            hssfWorkbook.setMissingCellPolicy(Row.CREATE_NULL_AS_BLANK); // 避免空指针异常  
    
            // 2、 获得Sheet  
            HSSFSheet sheet = hssfWorkbook.getSheetAt(0); // 获得第一个sheet  
    
    
            // 3、遍历每一行  
            for (Row row : sheet) {  
    
                if (row.getRowNum() == 0) {  
                    continue;  
                }  
                // 从第二行 开始解析  
                Region region = new Region();  
                String id = row.getCell(0).getStringCellValue(); // 获得第一个单元格信息  
                if (id.trim().equals("")) {  
                    // id 无值,跳过  
                    continue;  
                }  
                region.setId(id);  
                region.setProvince(row.getCell(1).getStringCellValue());  
                region.setCity(row.getCell(2).getStringCellValue());  
                region.setDistrict(row.getCell(3).getStringCellValue());  
                region.setPostcode(row.getCell(4).getStringCellValue());  
    
                //使用pinyin4j生成编码和简码  
                String str=region.getProvince()+region.getCity()+region.getDistrict();  
                str=str.replaceAll("省", "").replaceAll("市", "").replaceAll("区", "").replaceAll("县", "");  
                String[]  arr=PinYin4jUtils.getHeadByString(str);  
                StringBuffer sb = new StringBuffer();  
                for (String headChar : arr) {  
                    sb.append(headChar);  
                }  
                region.setShortcode(sb.toString()); // 简码  
    
                // 生成城市编码  
                region.setCitycode(PinYin4jUtils.hanziToPinyin(region.getCity(), ""));  
    
                //保存数据时出错  
                try {  
                    regionService.saveRegion(region);  
                } catch (Exception e) {  
                    // 导入region失败,记录日志  
                    LOG.error("区域导入失败,编号:" + region.getId(), e);  
                }  
    
            }  
    
            //返回json  
            Map<String,Object>  map=new HashMap<String,Object>();  
            map.put("result", "success");  
            map.put("msg", "区域导入完成");  
            ActionContext.getContext().put("map", map);  
    
            return "OCimport";  
        }  
    
    
        private File upload;  
        public void setUpload(File upload) {  
            this.upload = upload;  
        }  

    汉字转换为拼音的工具类为:(以下片段在文末项目中的位置是:/BOS/src/main/java/cn/tf/bos/utils/PinYin4jUtils.java)

    public class PinYin4jUtils {  
        /** 
         * 将字符串转换成拼音数组 
         *  
         * @param src 
         * @return 
         */  
        public static String[] stringToPinyin(String src) {  
            return stringToPinyin(src, false, null);  
        }  
    
        /** 
         * 将字符串转换成拼音数组 
         *  
         * @param src 
         * @return 
         */  
        public static String[] stringToPinyin(String src, String separator) {  
    
            return stringToPinyin(src, true, separator);  
        }  
    
        /** 
         * 将字符串转换成拼音数组 
         *  
         * @param src 
         * @param isPolyphone 
         *            是否查出多音字的所有拼音 
         * @param separator 
         *            多音字拼音之间的分隔符 
         * @return 
         */  
        public static String[] stringToPinyin(String src, boolean isPolyphone,  
                String separator) {  
            // 判断字符串是否为空  
            if ("".equals(src) || null == src) {  
                return null;  
            }  
            char[] srcChar = src.toCharArray();  
            int srcCount = srcChar.length;  
            String[] srcStr = new String[srcCount];  
    
            for (int i = 0; i < srcCount; i++) {  
                srcStr[i] = charToPinyin(srcChar[i], isPolyphone, separator);  
            }  
            return srcStr;  
        }  
    
        /** 
         * 将单个字符转换成拼音 
         *  
         * @param src 
         * @return 
         */  
        public static String charToPinyin(char src, boolean isPolyphone,  
                String separator) {  
            // 创建汉语拼音处理类  
            HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();  
            // 输出设置,大小写,音标方式  
            defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
            defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
    
            StringBuffer tempPinying = new StringBuffer();  
    
            // 如果是中文  
            if (src > 128) {  
                try {  
                    // 转换得出结果  
                    String[] strs = PinyinHelper.toHanyuPinyinStringArray(src,  
                            defaultFormat);  
    
                    // 是否查出多音字,默认是查出多音字的第一个字符  
                    if (isPolyphone && null != separator) {  
                        for (int i = 0; i < strs.length; i++) {  
                            tempPinying.append(strs[i]);  
                            if (strs.length != (i + 1)) {  
                                // 多音字之间用特殊符号间隔起来  
                                tempPinying.append(separator);  
                            }  
                        }  
                    } else {  
                        tempPinying.append(strs[0]);  
                    }  
    
                } catch (BadHanyuPinyinOutputFormatCombination e) {  
                    e.printStackTrace();  
                }  
            } else {  
                tempPinying.append(src);  
            }  
    
            return tempPinying.toString();  
    
        }  
    
        public static String hanziToPinyin(String hanzi) {  
            return hanziToPinyin(hanzi, " ");  
        }  
    
        /** 
         * 将汉字转换成拼音 
         *  
         * @param hanzi 
         * @param separator 
         * @return 
         */  
        public static String hanziToPinyin(String hanzi, String separator) {  
    
            // 创建汉语拼音处理类  
            HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();  
            // 输出设置,大小写,音标方式  
            defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
            defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
    
            String pinyingStr = "";  
            try {  
                pinyingStr = PinyinHelper.toHanyuPinyinString(hanzi, defaultFormat,  
                        separator);  
            } catch (BadHanyuPinyinOutputFormatCombination e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            return pinyingStr;  
        }  
    
        /** 
         * 将字符串数组转换成字符串 
         *  
         * @param str 
         * @param separator 
         *            各个字符串之间的分隔符 
         * @return 
         */  
        public static String stringArrayToString(String[] str, String separator) {  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < str.length; i++) {  
                sb.append(str[i]);  
                if (str.length != (i + 1)) {  
                    sb.append(separator);  
                }  
            }  
            return sb.toString();  
        }  
    
        /** 
         * 简单的将各个字符数组之间连接起来 
         *  
         * @param str 
         * @return 
         */  
        public static String stringArrayToString(String[] str) {  
            return stringArrayToString(str, "");  
        }  
    
        /** 
         * 将字符数组转换成字符串 
         *  
         * @param str 
         * @param separator 
         *            各个字符串之间的分隔符 
         * @return 
         */  
        public static String charArrayToString(char[] ch, String separator) {  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < ch.length; i++) {  
                sb.append(ch[i]);  
                if (ch.length != (i + 1)) {  
                    sb.append(separator);  
                }  
            }  
            return sb.toString();  
        }  
    
        /** 
         * 将字符数组转换成字符串 
         *  
         * @param str 
         * @return 
         */  
        public static String charArrayToString(char[] ch) {  
            return charArrayToString(ch, " ");  
        }  
    
        /** 
         * 取汉字的首字母 
         *  
         * @param src 
         * @param isCapital 
         *            是否是大写 
         * @return 
         */  
        public static char[] getHeadByChar(char src, boolean isCapital) {  
            // 如果不是汉字直接返回  
            if (src <= 128) {  
                return new char[] { src };  
            }  
            // 获取所有的拼音  
            String[] pinyingStr = PinyinHelper.toHanyuPinyinStringArray(src);  
    
            // 创建返回对象  
            int polyphoneSize = pinyingStr.length;  
            char[] headChars = new char[polyphoneSize];  
            int i = 0;  
            // 截取首字符  
            for (String s : pinyingStr) {  
                char headChar = s.charAt(0);  
                // 首字母是否大写,默认是小写  
                if (isCapital) {  
                    headChars[i] = Character.toUpperCase(headChar);  
                } else {  
                    headChars[i] = headChar;  
                }  
                i++;  
            }  
    
            return headChars;  
        }  
    
        /** 
         * 取汉字的首字母(默认是大写) 
         *  
         * @param src 
         * @return 
         */  
        public static char[] getHeadByChar(char src) {  
            return getHeadByChar(src, true);  
        }  
    
        /** 
         * 查找字符串首字母 
         *  
         * @param src 
         * @return 
         */  
        public static String[] getHeadByString(String src) {  
            return getHeadByString(src, true);  
        }  
    
        /** 
         * 查找字符串首字母 
         *  
         * @param src 
         * @param isCapital 
         *            是否大写 
         * @return 
         */  
        public static String[] getHeadByString(String src, boolean isCapital) {  
            return getHeadByString(src, isCapital, null);  
        }  
    
        /** 
         * 查找字符串首字母 
         *  
         * @param src 
         * @param isCapital 
         *            是否大写 
         * @param separator 
         *            分隔符 
         * @return 
         */  
        public static String[] getHeadByString(String src, boolean isCapital,  
                String separator) {  
            char[] chars = src.toCharArray();  
            String[] headString = new String[chars.length];  
            int i = 0;  
            for (char ch : chars) {  
    
                char[] chs = getHeadByChar(ch, isCapital);  
                StringBuffer sb = new StringBuffer();  
                if (null != separator) {  
                    int j = 1;  
    
                    for (char ch1 : chs) {  
                        sb.append(ch1);  
                        if (j != chs.length) {  
                            sb.append(separator);  
                        }  
                        j++;  
                    }  
                } else {  
                    sb.append(chs[0]);  
                }  
                headString[i] = sb.toString();  
                i++;  
            }  
            return headString;  
        }  
    }  

    在struts.xml中配置返回:(以下片段在文末项目中的位置是:/BOS/src/main/resources/struts.xml)

    <action name="region_*"  class="regionAction"  method="{1}">  
        <result  name="OCimport" type="json">  
            <param name="root">map</param>  
        </result>   
      </action>  

    这样的话就全部实现了上传的功能了。
    四、文件下载
    接下来说一下下载的功能:
    例如我们要将这个页面中的内容变为excel文件下载下来。

    这里写图片描述

    在下载的jsp页面中:
    点击按钮触发这个下载的函数,我们有一个函数:点击后跳转到action中。(以下片段在文末项目中的位置是:/BOS/src/main/webapp/WEB-INF/pages/base/subarea.jsp)

    function doExport(){  
        location.href="${pageContext.request.contextPath}/subarea_exportFile";  
    }  

    在action中:(以下片段在文末项目中的位置是:/BOS/src/main/java/cn/tf/bos/web/action/bc/SubareaAction.java)

    public String exportFile() throws IOException{  
        // 对文件名进行编码  
        String downloadFileName = "分区数据.xls";  
        // 获得用户使用浏览器类型  
        String agent = ServletActionContext.getRequest().getHeader("user-agent");  
    
        // 对下载文件名编码  
        downloadFileName = FileUtils.encodeDownloadFilename(downloadFileName, agent);  
        // 将结果放入值栈  
        ActionContext.getContext().put("downloadFileName", downloadFileName);  
    
        return "exportFile";  
    }  
    
    //文件下载流  
    public InputStream  getInputStream() throws IOException{  
        PageResponseBean pageResponseBean=(PageResponseBean) ServletActionContext.getRequest().getSession().getAttribute("pageResponseBean");  
        List<Subarea>  subareas=pageResponseBean.getRows();  
    
        HSSFWorkbook  hssfWorkbook=new HSSFWorkbook();  
    
        HSSFSheet sheet=hssfWorkbook.createSheet("分区数据");  
        HSSFRow  headRow=sheet.createRow(0);  
        headRow.createCell(0).setCellValue("分区编号");  
        headRow.createCell(1).setCellValue("关键字");  
        headRow.createCell(2).setCellValue("起始号");  
        headRow.createCell(3).setCellValue("结束号");  
        headRow.createCell(4).setCellValue("是否区分单双号号");  
        headRow.createCell(5).setCellValue("位置信息");  
    
        // 向excel写数据  
        for (Subarea subarea : subareas) {  
            // 每个分区一行  
            HSSFRow dataRow = sheet.createRow(sheet.getLastRowNum() + 1);  
            dataRow.createCell(0).setCellValue(subarea.getId());  
            dataRow.createCell(1).setCellValue(subarea.getAddresskey());  
            dataRow.createCell(2).setCellValue(subarea.getStartnum());  
            dataRow.createCell(3).setCellValue(subarea.getEndnum());  
            dataRow.createCell(4).setCellValue(subarea.getSingle());  
            dataRow.createCell(5).setCellValue(subarea.getPosition());  
        }  
    
        // 将数据缓存到字节数组  
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();  
        hssfWorkbook.write(arrayOutputStream);  
        arrayOutputStream.close();  
        byte[] data = arrayOutputStream.toByteArray();  
    
        // 再通过字节数组输入流读取数据  
        return new ByteArrayInputStream(data);  
    
    }  

    在struts.xml中配置:

    <result name="exportFile"  type="stream">  
                        <param name="contentType">application/vnd.ms-excel</param>  
                        <param name="contentDisposition">attachment;filename=${downloadFileName}</param>  
    </result>  

    这样我们就可以把数据下载出来了:

    这里写图片描述

    总结:文本使用的都是非常经典的技术来实现了文件一键上传、汉字转拼音、文件上传、文件下载的功能,具有非常好的实际意义,属于开发者必备技能之一。

    项目地址:https://github.com/sdksdk0/BOS


    [版权申明:本文系作者原创,转载请注明出处]
    文章出处:http://blog.csdn.net/sdksdk0/article/details/52557755

    作者:朱培 ID:sdksdk0

    展开全文
  • 最近遇见一个需要上传百兆大文件的需求,调研七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格...

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。

    在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格数据、上传影音文件等。如果文件体积比较大,或者网络条件不好时,上传的时间会比较长(要传输更多的报文,丢包重传的概率也更大),用户不能刷新页面,只能耐心等待请求完成。

    下面从文件上传方式入手,整理大文件上传的思路,并给出了相关实例代码,由于PHP内置了比较方便的文件拆分和拼接方法,因此服务端代码使用PHP进行示例编写。

    本文相关示例代码位于github上,主要参考

    聊聊大文件上传

    大文件切割上传

    文件上传的几种方式

    首先我们来看看文件上传的几种方式。

    普通表单上传

    使用PHP来展示常规的表单上传是一个不错的选择。首先构建文件上传的表单,并指定表单的提交内容类型为enctype="multipart/form-data",表明表单需要上传二进制数据。

    然后编写index.php上传文件接收代码,使用move_uploaded_file方法即可(php大法好…)

    form表单上传大文件时,很容易遇见服务器超时的问题。通过xhr,前端也可以进行异步上传文件的操作,一般由两个思路。

    文件编码上传

    第一个思路是将文件进行编码,然后在服务端进行解码,之前写过一篇在前端实现图片压缩上传的博客,其主要实现原理就是将图片转换成base64进行传递

    varimgURL = URL.createObjectURL(file);

    ctx.drawImage(imgURL, 0, 0);

    // 获取图片的编码,然后将图片当做是一个很长的字符串进行传递

    vardata= canvas.toDataURL( "image/jpeg", 0.5);

    在服务端需要做的事情也比较简单,首先解码base64,然后保存图片即可

    $imgData = $_REQUEST[ 'imgData'];

    $base64 = explode( ',', $imgData)[ 1];

    $img = base64_decode($base64);

    $url = './test.jpg';

    if(file_put_contents($url, $img)) {

    exit(json_encode( array(

    url => $url

    )));

    }

    base64编码的缺点在于其体积比原图片更大(因为Base64将三个字节转化成四个字节,因此编码后的文本,会比原文本大出三分之一左右),对于体积很大的文件来说,上传和解析的时间会明显增加。

    更多关于base64的知识,可以参考Base64笔记。

    除了进行base64编码,还可以在前端直接读取文件内容后以二进制格式上传

    // 读取二进制文件

    functionreadBinary(text){

    vardata = newArrayBuffer(text.length);

    varui8a = newUint8Array(data, 0);

    for( vari = 0; i < text.length; i++){

    ui8a[i] = (text.charCodeAt(i) & 0xff);

    }

    console.log(ui8a)

    }

    varreader = newFileReader;

    reader. = function{

    readBinary( this.result) // 读取result或直接上传

    }

    // 把从input里读取的文件内容,放到fileReader的result字段里

    reader.readAsBinaryString(file);

    formData异步上传

    FormData对象主要用来组装一组用 发送请求的键/值对,可以更加灵活地发送Ajax请求。可以使用FormData来模拟表单提交。

    letfiles = e.target.files // 获取input的file对象

    letformData = newFormData;

    formData.append( 'file', file);

    axios.post(url, formData);

    服务端处理方式与直接form表单请求基本相同。

    iframe无刷新页面

    在低版本的浏览器(如IE)上,xhr是不支持直接上传formdata的,因此只能用form来上传文件,而form提交本身会进行页面跳转,这是因为form表单的target属性导致的,其取值有

    _self,默认值,在相同的窗口中打开响应页面

    _blank,在新窗口打开

    _parent,在父窗口打开

    _top,在最顶层的窗口打开

    framename,在指定名字的iframe中打开

    如果需要让用户体验异步上传文件的感觉,可以通过framename指定iframe来实现。把form的target属性设置为一个看不见的iframe,那么返回的数据就会被这个iframe接受,因此只有该iframe会被刷新,至于返回结果,也可以通过解析这个iframe内的文本来获取。

    functionupload{

    varnow = + newDate

    varid = 'frame'+ now

    $( "body").append( `<iframe style="display:none;" name="${id}" id="${id}" />`);

    var$form = $( "#myForm")

    $form.attr({

    "action": '/index.php',

    "method": "post",

    "enctype": "multipart/form-data",

    "encoding": "multipart/form-data",

    "target": id

    }).submit

    $( "#"+id).on( "load", function{

    varcontent = $( this).contents.find( "body").text

    try{

    vardata = JSON.parse(content)

    } catch(e){

    console.log(e)

    }

    })

    }

    大文件上传

    现在来看看在上面提到的几种上传方式中实现大文件上传会遇见的超时问题,

    表单上传和iframe无刷新页面上传,实际上都是通过form标签进行上传文件,这种方式将整个请求完全交给浏览器处理,当上传大文件时,可能会遇见请求超时的情形

    通过fromData,其实际也是在xhr中封装一组请求参数,用来模拟表单请求,无法避免大文件上传超时的问题

    编码上传,我们可以比较灵活地控制上传的内容

    大文件上传最主要的问题就在于:在同一个请求中,要上传大量的数据,导致整个过程会比较漫长,且失败后需要重头开始上传。试想,如果我们将这个请求拆分成多个请求,每个请求的时间就会缩短,且如果某个请求失败,只需要重新发送这一次请求即可,无需从头开始,这样是否可以解决大文件上传的问题呢?

    综合上面的问题,看来大文件上传需要实现下面几个需求

    支持拆分上传请求(即切片)

    支持断点续传

    支持显示上传进度和暂停上传

    接下来让我们依次实现这些功能,看起来最主要的功能应该就是切片了。

    文件切片

    参考: 大文件切割上传

    编码方式上传中,在前端我们只要先获取文件的二进制内容,然后对其内容进行拆分,最后将每个切片上传到服务端即可。

    在Java中,文件FIle对象是Blob对象的子类,Blob对象包含一个重要的方法slice,通过这个方法,我们就可以对二进制文件进行拆分。

    下面是一个拆分文件的示例,对于up6来说开发者不需要关心拆分的细节,由控件帮助实现,开发者只需要关心业务逻辑即可。

    控件上传的时候会为每一个文件块数据添加相关的信息,开发者在服务端接收到数据后可以自已进行处理。

    服务器接收到这些切片后,再将他们拼接起来就可以了,下面是PHP拼接切片的示例代码

    对于up6来说,开发人员不需要进行拼接,up6已经提供了示例代码,已经实现了这个逻辑。

    保证唯一性,控件会为每一个文件块添加信息,如块索引,块MD5,文件MD5

    断点续传

    up6自带续传功能,up6在服务端已经保存了文件的信息,在客户端也保存了文件的进度信息。在上传时控件会自动加载文件进度信息,开发者不需要关心这些细节。在文件块的处理逻辑中只需要根据文件块索引来识别即可。

    此时上传时刷新页面或者关闭浏览器,再次上传相同文件时,之前已经上传成功的切片就不会再重新上传了。

    服务端实现断点续传的逻辑基本相似,只要在getUploadSliceRecord内部调用服务端的查询接口获取已上传切片的记录即可,因此这里不再展开。

    此外断点续传还需要考虑切片过期的情况:如果调用了mkfile接口,则磁盘上的切片内容就可以清除掉了,如果客户端一直不调用mkfile的接口,放任这些切片一直保存在磁盘显然是不可靠的,一般情况下,切片上传都有一段时间的有效期,超过该有效期,就会被清除掉。基于上述原因,断点续传也必须同步切片过期的实现逻辑。

    续传效果

     

    上传进度和暂停

    通过xhr.upload中的progress方法可以实现监控每一个切片上传进度。

    上传暂停的实现也比较简单,通过xhr.abort可以取消当前未完成上传切片的上传,实现上传暂停的效果,恢复上传就跟断点续传类似,先获取已上传的切片列表,然后重新发送未上传的切片。

    由于篇幅关系,上传进度和暂停的功能这里就先不实现了。

    实现效果:

     

    小结

    目前社区已经存在一些成熟的大文件上传解决方案,如七牛SDK,腾讯云SDK等,也许并不需要我们手动去实现一个简陋的大文件上传库,但是了解其原理还是十分有必要的。

    本文首先整理了前端文件上传的几种方式,然后讨论了大文件上传的几种场景,以及大文件上传需要实现的几个功能

    通过Blob对象的slice方法将文件拆分成切片

    整理了服务端还原文件所需条件和参数,演示了PHP将切片还原成文件

    通过保存已上传切片的记录来实现断点续传

    还留下了一些问题,如:合并文件时避免内存溢出、切片失效策略、上传进度暂停等功能,并没有去深入或一一实现,继续学习吧

    后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/

    展开全文
  • 最近遇见一个需要上传超大大文件的需求,调研七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格...

    最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。

    在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格数据、上传影音文件等。如果文件体积比较大,或者网络条件不好时,上传的时间会比较长(要传输更多的报文,丢包重传的概率也更大),用户不能刷新页面,只能耐心等待请求完成。

    下面从文件上传方式入手,整理大文件上传的思路,并给出了相关实例代码,由于PHP内置了比较方便的文件拆分和拼接方法,因此服务端代码使用PHP进行示例编写。

    本文相关示例代码位于github上,主要参考

    聊聊大文件上传

    大文件切割上传

    文件上传的几种方式

    首先我们来看看文件上传的几种方式。

    普通表单上传

    使用PHP来展示常规的表单上传是一个不错的选择。首先构建文件上传的表单,并指定表单的提交内容类型为enctype="multipart/form-data",表明表单需要上传二进制数据。

    然后编写index.php上传文件接收代码,使用move_uploaded_file方法即可(php大法好…)

    form表单上传大文件时,很容易遇见服务器超时的问题。通过xhr,前端也可以进行异步上传文件的操作,一般由两个思路。

    文件编码上传

    第一个思路是将文件进行编码,然后在服务端进行解码,之前写过一篇在前端实现图片压缩上传的博客,其主要实现原理就是将图片转换成base64进行传递

    varimgURL = URL.createObjectURL(file);

    ctx.drawImage(imgURL, 0, 0);

    // 获取图片的编码,然后将图片当做是一个很长的字符串进行传递

    vardata= canvas.toDataURL( "image/jpeg", 0.5);

    在服务端需要做的事情也比较简单,首先解码base64,然后保存图片即可

    $imgData = $_REQUEST[ 'imgData'];

    $base64 = explode( ',', $imgData)[ 1];

    $img = base64_decode($base64);

    $url = './test.jpg';

    if(file_put_contents($url, $img)) {

    exit(json_encode( array(

    url => $url

    )));

    }

    base64编码的缺点在于其体积比原图片更大(因为Base64将三个字节转化成四个字节,因此编码后的文本,会比原文本大出三分之一左右),对于体积很大的文件来说,上传和解析的时间会明显增加。

    更多关于base64的知识,可以参考Base64笔记。

    除了进行base64编码,还可以在前端直接读取文件内容后以二进制格式上传

    // 读取二进制文件

    functionreadBinary(text){

    vardata = newArrayBuffer(text.length);

    varui8a = newUint8Array(data, 0);

    for( vari = 0; i < text.length; i++){

    ui8a[i] = (text.charCodeAt(i) & 0xff);

    }

    console.log(ui8a)

    }

    varreader = newFileReader;

    reader. = function{

    readBinary( this.result) // 读取result或直接上传

    }

    // 把从input里读取的文件内容,放到fileReader的result字段里

    reader.readAsBinaryString(file);

    formData异步上传

    FormData对象主要用来组装一组用 发送请求的键/值对,可以更加灵活地发送Ajax请求。可以使用FormData来模拟表单提交。

    letfiles = e.target.files // 获取input的file对象

    letformData = newFormData;

    formData.append( 'file', file);

    axios.post(url, formData);

    服务端处理方式与直接form表单请求基本相同。

    iframe无刷新页面

    在低版本的浏览器(如IE)上,xhr是不支持直接上传formdata的,因此只能用form来上传文件,而form提交本身会进行页面跳转,这是因为form表单的target属性导致的,其取值有

    _self,默认值,在相同的窗口中打开响应页面

    _blank,在新窗口打开

    _parent,在父窗口打开

    _top,在最顶层的窗口打开

    framename,在指定名字的iframe中打开

    如果需要让用户体验异步上传文件的感觉,可以通过framename指定iframe来实现。把form的target属性设置为一个看不见的iframe,那么返回的数据就会被这个iframe接受,因此只有该iframe会被刷新,至于返回结果,也可以通过解析这个iframe内的文本来获取。

    functionupload{

    varnow = + newDate

    varid = 'frame'+ now

    $( "body").append( `<iframe style="display:none;" name="${id}" id="${id}" />`);

    var$form = $( "#myForm")

    $form.attr({

    "action": '/index.php',

    "method": "post",

    "enctype": "multipart/form-data",

    "encoding": "multipart/form-data",

    "target": id

    }).submit

    $( "#"+id).on( "load", function{

    varcontent = $( this).contents.find( "body").text

    try{

    vardata = JSON.parse(content)

    } catch(e){

    console.log(e)

    }

    })

    }

    大文件上传

    现在来看看在上面提到的几种上传方式中实现大文件上传会遇见的超时问题,

    表单上传和iframe无刷新页面上传,实际上都是通过form标签进行上传文件,这种方式将整个请求完全交给浏览器处理,当上传大文件时,可能会遇见请求超时的情形

    通过fromData,其实际也是在xhr中封装一组请求参数,用来模拟表单请求,无法避免大文件上传超时的问题

    编码上传,我们可以比较灵活地控制上传的内容

    大文件上传最主要的问题就在于:在同一个请求中,要上传大量的数据,导致整个过程会比较漫长,且失败后需要重头开始上传。试想,如果我们将这个请求拆分成多个请求,每个请求的时间就会缩短,且如果某个请求失败,只需要重新发送这一次请求即可,无需从头开始,这样是否可以解决大文件上传的问题呢?

    综合上面的问题,看来大文件上传需要实现下面几个需求

    支持拆分上传请求(即切片)

    支持断点续传

    支持显示上传进度和暂停上传

    接下来让我们依次实现这些功能,看起来最主要的功能应该就是切片了。

    文件切片

    参考: 大文件切割上传

    编码方式上传中,在前端我们只要先获取文件的二进制内容,然后对其内容进行拆分,最后将每个切片上传到服务端即可。

    在Java中,文件FIle对象是Blob对象的子类,Blob对象包含一个重要的方法slice,通过这个方法,我们就可以对二进制文件进行拆分。

    下面是一个拆分文件的示例,对于up6来说开发者不需要关心拆分的细节,由控件帮助实现,开发者只需要关心业务逻辑即可。

    控件上传的时候会为每一个文件块数据添加相关的信息,开发者在服务端接收到数据后可以自已进行处理。

    服务器接收到这些切片后,再将他们拼接起来就可以了,下面是PHP拼接切片的示例代码

    对于up6来说,开发人员不需要进行拼接,up6已经提供了示例代码,已经实现了这个逻辑。

    保证唯一性,控件会为每一个文件块添加信息,如块索引,块MD5,文件MD5

    断点续传

    up6自带续传功能,up6在服务端已经保存了文件的信息,在客户端也保存了文件的进度信息。在上传时控件会自动加载文件进度信息,开发者不需要关心这些细节。在文件块的处理逻辑中只需要根据文件块索引来识别即可。

    此时上传时刷新页面或者关闭浏览器,再次上传相同文件时,之前已经上传成功的切片就不会再重新上传了。

    服务端实现断点续传的逻辑基本相似,只要在getUploadSliceRecord内部调用服务端的查询接口获取已上传切片的记录即可,因此这里不再展开。

    此外断点续传还需要考虑切片过期的情况:如果调用了mkfile接口,则磁盘上的切片内容就可以清除掉了,如果客户端一直不调用mkfile的接口,放任这些切片一直保存在磁盘显然是不可靠的,一般情况下,切片上传都有一段时间的有效期,超过该有效期,就会被清除掉。基于上述原因,断点续传也必须同步切片过期的实现逻辑。

    续传效果

     

    上传进度和暂停

    通过xhr.upload中的progress方法可以实现监控每一个切片上传进度。

    上传暂停的实现也比较简单,通过xhr.abort可以取消当前未完成上传切片的上传,实现上传暂停的效果,恢复上传就跟断点续传类似,先获取已上传的切片列表,然后重新发送未上传的切片。

    由于篇幅关系,上传进度和暂停的功能这里就先不实现了。

    实现效果:

     

    小结

    目前社区已经存在一些成熟的大文件上传解决方案,如七牛SDK,腾讯云SDK等,也许并不需要我们手动去实现一个简陋的大文件上传库,但是了解其原理还是十分有必要的。

    本文首先整理了前端文件上传的几种方式,然后讨论了大文件上传的几种场景,以及大文件上传需要实现的几个功能

    通过Blob对象的slice方法将文件拆分成切片

    整理了服务端还原文件所需条件和参数,演示了PHP将切片还原成文件

    通过保存已上传切片的记录来实现断点续传

    还留下了一些问题,如:合并文件时避免内存溢出、切片失效策略、上传进度暂停等功能,并没有去深入或一一实现,继续学习吧

    后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/ 
    欢迎入群一起讨论:374992201 

    展开全文
  • 第一篇是如何用八爪鱼设置爬取下载地址:10分钟教你爬取科创板反馈意见如果还是不会设置,就看第二篇,我把设置好的配置文件上传了,直接在八爪鱼导入配置文件就能爬:科创板爬虫,这次不用自己设置爬取下载地址...
  • 最近遇见一个需要上传百兆大文件的需求,调研七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格...
  • 通过excel的导入导出练习,使用NPOI组件还是方便一点,所有下面就以NPOI下的导入导出给出实例,通过网页导入excel表,首先上传,再导入数据到库,这里为了方便就导入到库中,直接拿到数据。导出方法比较多。 ...
  • 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格数据、上传影音文件等。如果文件体积比较大,或者网络条件不好时,上传的时间会比较长(要传输更多的报文,丢包重传的概率也更大)...
  • 最近临近期末,单片机考试快要到,我写一个python脚本,可以把学习通网页上的题保存到excel里面,但是一个人的题终究不是题库,所以我想找多一点人,把题库里的题都套出来,所以需要大家的帮忙,最后所有的题库...
  • 因为工作的需要,要在网页上添加很多学员的信息,但是公司审计让直接导入数据库,而且开发也没有涉及批量上传的功能,只好自己动手用Python写一个批量创建学生信息的程序。 实现思路: 我们首先看我们需要填的...
  • 最近遇见一个需要上传超大大文件的需求,调研七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格...
  • 点击保存,另一边b就自动更新,或者b更改完,都不用点击保存,a那边就能自动同步,有没有这种软件或者网页,不要告诉我360云盘,百度云盘,微部落等等等这些上传文件就能多人同时编辑的,但是这样能起到实时...
  • Excel文档导入

    2019-07-29 08:05:21
    导出是把显示在当前页面上的数据以Excel的形式下载并保存在本地以供离线浏览及编辑,导入是按照当前页面上的形式进入导入并且把数据显示在页面上,导入到当前页面必须按照网页上下载下来的模板进行上传,如果按照...
  • Excel导入/导出

    2015-08-05 11:09:21
    注释很详尽,就多说,简单解释下原理:  GetExcelSheet方法:导入功能。原理为把Excel上传至服务器,然后把Excel当作数据库读数据到DataTable返回,然后删除服务器端的Excel,最后对返回的DataTable进行数据...
  • 然后notepad 打开inc/conn.Asp查看参数与网页对应关系。 然后打开默认自带的数据库对比查询结果,查看对应关系。 xls版打开方式:可以直接双击打开,xls格式的Excel文件查看。 使用须知: 1. 请勿将本系统用于...
  • MFC工程已经上传,下载地址:操作Excel文件的参考文档,都是网页的pdf版,下载地址:操作Xml文件的参考文档,同样是网页的pdf版,下载地址:下面是相应步骤:1. 建立MFC工程,MDI,其他默认即可。2. 操作
  • 财务的小姑娘一直嚷嚷着要我给做个从网页上导入到数据库的工具,终于心一软答应她. 下面叙述一下我asp.net 将Excel导入到Sql2005或2000的思路和步骤: 1、将Excel文件上传到服务器端 这个我想详细讲,网上一...
  • 我是网页制作的初学者,只看过html语言,... 那个excel表格的话,我想着是利用excel自带的功能,存为html格式之后再上传到服务器上,但这之后的功能该怎么实现就知道...有没有现成的代码或者网页模板之类的?
  • 最近听朋友说很苦恼自己有很多文档需要上传,但是文档格式不对需要转化为pdf才能上传,我说直接转化就行,她说网上需要下载软件而且需要付费。今天利用空闲时间给大家做一个文档转化大全。1、word、excel、ppt等...
  • 近日公司要搞一个日常的文档管理的东东,可以上传、下载各种文件,如果是office文件呢还必须得支持预览功能,其他的都好说但是唯独office预览功能比较麻烦,但是做,废话多说一步步来吧。分析下网易邮箱...
  • 在为大家讲解新的知识之前内,先为大家补充一下上一篇文章中标签内容的视频讲解,由于小丸子的失误导致视频优酷没有上传成功只能为大家提供网盘地址,为...对于网页有些了解的同学就说:“小丸子,我们现在都怎么
  • 这个bug:出现的情形是,我在弹窗上传了一个Excel文件,然后返回给网页信息,关闭弹窗。然而弹窗关闭不了,然后一直提示这个错误,最后发现原因居然是浏览器兼容性问题,个别浏览器就好使了。 问题原因:&lt;...
  • 实例264 出现在任务栏上的程序 360 实例265 怎样调用外部的EXE文件 361 实例266 关闭外部已开启的程序 362 7.10 程序运行 363 实例267 防止程序多次运行 363 实例268 程序运行时禁止关机 364 实例269...
  • 实例264 出现在任务栏上的程序 360 实例265 怎样调用外部的EXE文件 361 实例266 关闭外部已开启的程序 362 7.10 程序运行 363 实例267 防止程序多次运行 363 实例268 程序运行时禁止关机 364 实例269...
  • 站内搜索、栏目管理、视频播放(完全模仿优酷视频页面)、焦点图、静态...上传图片、搜索引擎优化设置、数据备份恢复、伪静态设置、网上商城、订单管理、在线支付(支持支付宝、财付通、块钱等第三方支付平台)、网站...

空空如也

空空如也

1 2 3 4 5 6
收藏数 105
精华内容 42
关键字:

网页上传不了excel