文件下载
a.download
文件下载一般使用a标签,当给a标签download
属性时,在点击时就会下载访问href请求的文件,但是只有在href指向的地址是同源时才会下载,不同源时只会常规跳转。
download的值就是下载的文件名。
URL.createObjectURL
会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
以下代码会下载一个html文件。
let str = `
<div>
<span>hellowrold</span>
</div>
`
let blob = new Blob([str], {
type: 'text/html'
})
const a = document.createElement('a');
a.download = '我的文件';
a.href = URL.createObjectURL(blob);
a.click()
图片预览
利用上面提到的特性可以实现图片预览
<body>
<input type='file' id='input' />
<script>
input.oninput = function (e) {
const img = new Image()
img.src = URL.createObjectURL(e.target.files[0]);
document.body.appendChild(img)
}
</script>
</body>
以上创建url的方式时同步的,还可以用FileReader
异步读取
<body>
<input type='file' id='input' />
<script>
input.oninput = function (e) {
const img = new Image()
const fileReader = new FileReader();
fileReader.onload = function () {
img.src = fileReader.result;
}
fileReader.readAsDataURL(e.target.files[0])
document.body.appendChild(img)
}
</script>
</body>
文件上传
服务端
const express = require('express');
const path = require('path');
const multiparty = require('multiparty');
const bodyParser = require('body-parser');
const app = express();
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
router.post('/upload', async (req, res) => {
const form = new multiparty.Form({
uploadDir: 'temp',
});
form.parse(req);
form.on('file', () => {
console.log('上传成功');
});
res.send('上传成功');
});
app.listen(3000, () => {
console.log('connect port 3000');
});
前端
<body>
<input type='file' id='input' />
<script>
input.oninput = function (e) {
const file = e.target.files[0];
const formData = new FormData()
formData.append('file', file)
axios({
url: '/upload',
data: formData,
method: 'POST',
headers: {
"Content-Type": "multipart/form-data"
}
}).then(res => {
index++;
upload()
})
}
</script>
</body>
分片上传
File
对象继承自Blob
对象,Blob
对象有个方法slice
。
所以我们可以使用该方法将文件分割成小块的blob,然后再生成小块的file。
前端代码根据上面的做改动
<body>
<input type='file' id='input' />
<script>
let chunkSize = 1024 * 10, index = 0;
input.oninput = upload;
function upload(e) {
let start = index * chunkSize
const file = input.files[0];
if (start > file.size) {
// 分片上传完成,发送合并分片的请求
axios.post('/merge', { name: file.name })
return;
};
const [filename, ext] = file.name.split('.')
const blob = file.slice(start, start + chunkSize)
const blobName = `${filename}.${index}.${ext}`
const blobFile = new File([blob], blobName)
const formData = new FormData()
formData.append('file', blobFile)
axios({
url: '/upload',
data: formData,
method: 'POST',
headers: {
"Content-Type": "multipart/form-data"
}
}).then(res => {
index++;
upload()
})
}
</script>
</body>
文件分片上传前端部分就实现了,后端接收到分片文件之后需要拼一下。
const express = require('express');
const path = require('path');
const multiparty = require('multiparty');
const fse = require('fs-extra');
const fs = require('fs');
const bodyParser = require('body-parser');
const app = express();
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const UPLOAD_DIR = path.join(__dirname, '/public/upload');
app.post('/upload', async (req, res) => {
const form = new multiparty.Form({
uploadDir: 'temp',
});
form.parse(req);
form.on('file', async (name, chunk) => {
// 存放切片的目录
let chunkDir = `${UPLOAD_DIR}/${chunk.originalFilename.split('.')[0]}`;
if (!fse.existsSync(chunkDir)) {
await fse.mkdirs(chunkDir);
}
// 将分片按索引编号再次命名
let dPath = path.join(chunkDir, chunk.originalFilename.split('.')[1]);
// 将分片从临时目录移动到分片的存储目录
await fse.move(chunk.path, dPath, { overwrite: true });
});
res.send('上传成功');
});
app.post('/merge', async (req, res) => {
// 根据传来的文件名进行合并
let name = req.body.name;
let fname = name.split('.')[0];
// 获取文件名的所有分片
let chunkDir = path.join(UPLOAD_DIR, fname);
let chunks = await fse.readdir(chunkDir);
chunks
.sort((a, b) => a - b)
.forEach(chunkPath => {
fs.appendFileSync(
// 合并文件
path.join(UPLOAD_DIR, name),
fs.readFileSync(`${chunkDir}/${chunkPath}`)
);
});
// 合并完成后删除分片目录
fse.removeSync(chunkDir);
res.send({
message: '合并成功',
url: `http://localhost:3000/upload/${name}`,
});
});
app.listen(3000, () => {
console.log('connect port 3000');
});