上传文件应该是除了提交数据以外最常用的一种功能了,上篇已经说了使用原生net提交数据,上传文件和提交数据主要有2点不同,1.请求头不同 2.要选择本地待上传文件。
下面就以上传图片为例。
一、前段html页面
创建一个很简单的表单,只有姓名,性别,个人备注3个字段,
ID为uploadFilePath 的DIV : 选择图片后,文件的路径显示在这里
ID为img的span是图片上传成功后,将图片显示出来
<form id="hmForm">
<input type="text" id="name" name="name" value="李四"/>
<input type="text" id="age" name="age" value="28"/>
<textarea id="cont" name="cont" value=""></textarea>
<br/>
<div id="uploadFilePath"></div>
<input type="button" value="选择文件" id="selectFile"/>
<input type="button" value="上传文件" id="uploadFile"/>
<br/>
<span id="img"></span>
</form>
二、引入jQuery
<script src="./js/jquery.min.js"></script>
三、编写上传的JS
文件上传简单处理的话只有2步, 1.选择文件 2.上传文件 ;(不做大小判断)
1.选择文件
在以前WEB方式下,都是用 file表单处理,但是通过表单选择文件,得到的路径是被系统处理过的,处理起来非常麻烦,Electron提供了showOpenDialog这个API,可以直接获取文件的路径。定义一个选择文件的方法
/**
* @param fileExt 上传文件后缀
* @param isMulti 是否多文件上传
* @param callbackName
* @param
*/
openFile : (fileExt,isMulti,callbackName,options)=>{
let properties = "openFile";
if(isMulti){
properties+=",multiSelections";
}
fileExt = fileExt != ""?fileExt:"*";
dialog.showOpenDialog(childWindow,{
title:"选择文件",
properties: properties.split(","),
filters: [
{ name: 'file', extensions: fileExt.split(",") }
]
}).then(result => {
upload.callbackFunction(callbackName,result,options);
}).catch(err => {
console.log(err)
upload.alert("提示消息","出错了:"+err);
});
},
2.上传文件
用自带的net和node的fs.createReadStream
postFile : (url,uploadFilePath,callbackName,formId)=>{
if(url==""){
upload.alert("提交到后台的路径不能为空!");
return;
}
if(uploadFilePath==""){
upload.alert("上传的文件不能为空!");
return;
}
let data = $("#"+formId).serialize();
if(data!=""){
const bs = url.indexOf("?")>0?"&":"?";
url +=bs+data;
}
console.log(url)
const option = upload.getOptions(url);
const boundaryKey = '--'+Math.random().toString(16);
const fileName= upload.getFileName(uploadFilePath);
let request = net.request(option);
request.setHeader("Content-Type",'multipart/form-data; boundary=' + boundaryKey);
request.setHeader("Connection","keep-alive");
// 写入内容头部
request.write(`--${boundaryKey}\r\nContent-Disposition: form-data; name="Filedata"; filename="${fileName}"\r\n\r\n`);
request.on('response', (response) => {
response.on('data', (result) => {
console.log(`BODY: ${result}`);
result = JSON.parse(result);
upload.alert("提示信息",result.code,callbackName,result);
});
response.on('end', () => {
console.log('响应中已无数据')
});
});
// 写入内容
const fstat = fs.statSync(uploadFilePath);
const size= fstat.size;
const readStream = fs.createReadStream(uploadFilePath,{
highWaterMark:15*1024, //文件一次读多少字节,默认 64*1024
autoClose:true, //默认读取完毕后自动关闭
start:0, //读取文件开始位置
end:size, //流是闭合区间 包含start也含end
});
readStream.on("open",(data)=>{
console.log('打开了',data)
});
readStream.on("data",(data)=>{
console.log("已经读取的字节数",readStream.bytesRead);
});
readStream.pipe(request, { end: false });
readStream.on('end', function () {
console.log("end")
// 写入尾部
request.end('\r\n--' + boundaryKey + '--\r\n');
});
}
这里有个地方要注意 :highWaterMark 这个参数要小于16KB。
四、运行程序效果
第一步:运行
第二步:点击“选择文件”按钮 ,并选择要上传的文件
第三步:点击“上传文件”按钮
文件上传成功后,会弹出成功的提示框(3),java控制台也会显示提交过去的数据(2)
第四步:点击“确定”按钮后,显示图片
还有一些自定义的方法,我就不贴出来了,看方法名称应该也能知道是干什么的,或者去下载我的demo文档
demo : https://download.csdn.net/download/zhuiyue82/12882527
PS:demo里的代码只是最简单处理,正式使用还有很多地方需要优化,例如参数的判断,文件大小的判断,上传进度条显示等等,而且一次也只能上传一个文件,多个文件的上传,可以根据代码改造就能实现。
如果有需要一次性上传多个文件的朋友,也可以在文章下留言,哈哈,忽悠点评论数哈哈哈。