上传文件的基本方法
<input type="file" ref="input"/>
const input = ref()
const upload=async()=>{
if (input.value.files[0]) {
let uploadFile = new FormData()
uploadFile.append('file',input.value.files[0])
uploadFile.append('bodyParams1',bodyParams1)
const res = await fileApi(uploadFile,{params:{???:???},headers:{???:???}})
}
}
前端上传+后台处理
1,后台接收并保存上传的文件
uploadRouter.post('/post', async (req, res) => {
const files = req.files
for (const file of files) {
// 先保存到本地文件
// 如果报错:找不到文件,把__dirname换成process.cwd()
fs.renameSync(
path.join(__dirname, '../public/upload/temp/', file.filename),
path.join(__dirname, '../public/upload/', file.originalname),
)
//读取本地文件
const result = fs.readFileSync(
path.join(__dirname, '../public/upload/', file.originalname),
)
//存到数据库,此时的文件类型为Blob
const uploadQuery =
'insert into music (name,content,uid) values (?,?,?)'
const r = await db.database(uploadQuery, [
file.originalname,
result,
req.query.id,
])
if (r.err) {
//如果存到数据库失败了,删除本地的,并返回失败信息
fs.unlinkSync(
path.join(__dirname, '../public/upload/', file.originalname),
)
res.send({
code: '500',
msg: '上传文件失败',
})
} else {
//成功
res.send({
code: '200',
data: {
file: file.originalname,
user: req.query.name,
},
})
}
}
})
2,根据请求取出文件
uploadRouter.get('/get', async (req, res) => {
const { name, id } = req.query
const getQuery = 'select * from music where uid=?'
const result = await db.database(getQuery, [id])
if (result.err) {
res.send({
code: '201',
msg: '获取失败',
})
return
}
//获取成功后对每一项进行操作
result.res.forEach(item => {
delete item.uid
item.user = name
})
//返回数据
res.send({
code: '200',
msg: '获取成功',
data: result.res,
})
// 将数据库的文件读取到本地
for (const musicItem of result.res) {
fs.writeFileSync(
path.join(__dirname, '../public/', musicItem.name),
musicItem.content,
)
}
})
3,使用请求接口返回的数据
//从后端返回的buffer类型的数据
const buffer = [?,?,?];
let dataArray = new Uint8Array(buffer)
// 创建 Blob 对象,构造函数接收的是数组
const blob = new Blob(dataArray);
// 创建包含 Blob 对象的 URL
const imageURL = URL.createObjectURL(blob);
// 创建 <img> 元素来显示图片,也可以为音频,视频
const imgElement = document.createElement('img');
imgElement.src = imageURL;
// 记得在不需要的时候释放临时 URL
URL.revokeObjectURL(imageURL);
分片上传
使用递归将文件分割,进行分片上传
let btnFile = document.querySelector("#btnFile")
let chunkSize = 1024 * 1024 * 20
//使用了递归
function handleChange(index = 0) {
const file = btnFile.files[0]
const lastIndex = file.name.lastIndexOf("."); // 获取最后一个点的索引
const ftext = file.name.substring(lastIndex + 1); // 截取点之后的内容作为扩展名
const fname = file.name.substring(0, lastIndex); // 截取从开头到最后一个点之前的内容作为文件名
let start = index * chunkSize; // 当前分片的起始索引
if (start > file.size) {
return
}
let blob = file.slice(start, start + chunkSize);
let bolbName = encodeURIComponent(`${fname}.${index}.${ftext}`);
let blobFile = new File([blob], bolbName);
let formData = new FormData();
formData.append("currentChunks", index + 1)
formData.append("totalChunks", Math.ceil(file.size / chunkSize))
formData.append("file", blobFile)
axios.post('/upload/big-file', formData).then(res => {
console.log(res);
handleChange(++index)
})
}
下载图片
直接将图片的地址赋值给a标签后,即使设置了download属性,默认行为也是直接在网页中打开图片。只有将其转换为二进制的数据流,再用临时的url去访问下载,才可以成功。
import axios from "axios"
/**
* @desc 文件下载
* @param {String} url 图片的网络地址
* @param {String} filename 定义下载下来的文件名叫什么
* @param {object} loadObj 可以是一个proxy对象,它的loading属性控制外层的加载动画
*/
export const downFile = (url, filename,loadObj) => {
loadObj.loading = true
axios.get(url, { responseType: "blob" }).then((response) => {
const link = document.createElement("a")
link.href = window.URL.createObjectURL(new Blob([response.data]))
link.setAttribute("download", filename)
document.body.appendChild(link)
link.click()
loadObj.loading = false
})
}
将base64格式的图片转为File
//base为base64图片具体内容;name为定义的图片名字,需要带后缀(如name.png)
//返回值为可用来上传的File
export const useBase64ToFile = (base: string, name: string): File => {
const arr = base.split(',')
const mime = arr[0]!.match(/:(.*?);/)![1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], name, { type: mime })
}