MySQL可以存放几乎任何类型的数据(图片、文档、压缩包等),但这不是最好的解决方案,正常情况下都是在数据库中存放文件路径,图片、音乐、视频、压缩包、文档等文件存放在硬盘上。
2018.8.4更新:
在传输文件时,multer().array()
设置的字段属性应该和前端中的<input>标签的name
属性一致,否则会产生错误:“unexpected field: ......
”
1. 代码
index.html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Upload File</title>
</head>
<body>
<h2>Select a File</h2>
<form action="/upload_file" method="POST" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="Submit">
</form>
<form action="/delete_all_file" method="GET">
<input type="submit" value="删除所有文件">
</form>
<form action="/delete_cache" method="GET">
<input type="submit" value="清除缓存">
</form>
</body>
</html>
server.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134/**
* 创建服务器
* - 实现文件传输并合理存储
* - 实现磁盘文件和数据库文件信息的同步一体
* - 接收文件完毕后自动删除缓存
* - 可以在前端删除所有文件(同步修改数据库)
*/
/********************************
************ 预定义 **************
*********************************/
//依赖
var express = require('express');
var app = express();
var mysql = require('mysql');
var fs = require('fs');
var bodyParser = require('body-parser');
var multer = require('multer');
var clear = require('./clear');
var db = require('./db');
// 中间件
app.use(bodyParser.urlencoded({ extended: false })); // 只解析请求中的字符串和数组(本例暂时没用到)
// 设置文件缓存的目录
var upload = multer({ dest: './uploadFiles/tmp/'});
/********************************
********************************
*********************************/
// 首页
app.get('/', function (req, res) {
res.sendFile(__dirname + '/' + 'index.html');
});
// 响应文件上传请求
app.post('/upload_file', upload.array('file'), function (req, res) {
// 文件信息
if (req.files[0]){
console.log("----------接收文件----------\n");
console.log(req.files[0]);
}
// 存储
var des_file = __dirname + "/uploadFiles/" + req.files[0].fieldname + "/" + req.files[0].originalname;
fs.readFile(req.files[0].path, function (error, data) {
if (error) {
return console.error(error);
}
fs.writeFile(des_file, data, function (err) {
if (err) {
// 接收失败
console.log(err);
}else {
// 接收成功
var response = {
message: 'File uploaded successfully!',
filename: req.files[0].originalname
};
console.log('\n----------SAVING-----------\n');
// 删除缓存文件
fs.unlink(req.files[0].path, function(err){
if (err){
return console.error(err);
}
})
// 将文件信息写入数据库
var time = new Date().toJSON();
var addSQL = 'INSERT INTO uploadfiles(fieldname, originalName, tmpName, encoding, mimetype, size, path, tmpPath, addTime) VALUES(?,?,?,?,?,?,?,?,?)';
var addSqlParams = [req.files[0].fieldname, req.files[0].originalname, req.files[0].filename,
req.files[0].encoding, req.files[0].mimetype, req.files[0].size, des_file, __dirname + '/' + req.files[0].path, time];
// 插入数据
db.connection.query(addSQL, addSqlParams, function (err, result) {
if (err) {
return console.error(err);
}else {
console.log(JSON.stringify(response));
console.log(result);
console.log('\n----------SUCCEED----------\n\n');
res.json( response );
}
})
}
});
});
});
// 删除所有文件
app.get('/delete_all_file', function (req, res) {
if (clear.clearAllFile()) {
console.log('Clear all files successfully!');
res.send('<h1>Clear all files successfully!</h1>');
} else {
res.send('<h1>Error: When clear all files!</h1>');
}
})
// 删除缓存
app.get('/delete_cache', function (req, res) {
if (clear.clearCache()) {
console.log('Clear cache successfully!');
res.send('<h1>Clear cache successfully!</h1>');
} else {
res.send('<h1>Error: When clear cache!</h1>');
}
})
// 获取本地IPv4
function getLocalIPv4 () {
interfaces = require("os").networkInterfaces();
for(var devName in interfaces){//遍历所有连接
var iface = interfaces[devName];
for(var i=0; i<iface.length; i++){//遍历每个连接中的不同地址(family为标识)
var alias = iface[i];
if(alias.family == 'IPv4' && alias.address != '127.0.0.1' && !alias.internal)//该判断保证为有效的IPv4地址(排除了内部地址和本地地址)
{
return alias.address;
}
}
}
}
// 监听
var server = app.listen(3333, getLocalIPv4(), function () {
var host = server.address().address;
var port = server.address().port;
console.log('访问地址为:http://%s:%s', host, port);
});
依赖项,package.json1
2
3
4
5
6
7
8
9
10
11
12{
"name": "node-file",
"version": "0.0.1",
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.3",
"fs": "0.0.1-security",
"multer": "^1.3.1",
"mysql": "^2.16.0"
}
}
clear.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48/**
* 文件清理 + 缓存清理
*/
// 依赖
var fs = require('fs');
var db = require('./db');
var clearAllFile = function () {
fs.readdir('./uploadFiles/file', function (error, files) {
if (error) {
return console.error(error);
}
for (var i=0; i<files.length; i++) {
fs.unlink(__dirname + "/uploadFiles/file/" + files[i].toString(), function (err) {
if (err) {
return console.error(err);
}
})
// 在数据库中删除文件信息
var dropSql = 'delete from uploadfiles where originalName=\''+ files[i].toString()+'\'';
db.connection.query(dropSql, function (err, result) {
if (err) {
return console.error(err);
}
})
}
})
return true;
}
var clearCache = function () {
fs.readdir('./uploadFiles/tmp', function (error, files) {
if (error) {
return console.error(error);
}
for (var i=0; i<files.length; i++) {
fs.unlink(__dirname + "/uploadFiles/tmp/" + files[i].toString(), function (err) {
if (err) {
return console.error(err);
}
})
}
})
return true;
}
exports.clearAllFile = clearAllFile;
exports.clearCache = clearCache;
db.js1
2
3
4
5
6
7
8
9
10
11
12
13/**
* 连接数据库
*/
var mysql = require('mysql');
var connection = mysql.createConnection({
user: 'mysqljs',
password: 'mysqljs',
database: 'uploadfiles'
});
connection.connect();
exports.connection = connection;
2. 思路
整体思路:在前端选择文件并上传至服务器,服务器接收文件同时删除缓存;接收文件成功后,将文件信息读取存入数据库中;删除文件时,同步删除数据库中的相关信息。
详细步骤:
首先我们需要依赖以下几个npm模块:
- express - 搭建服务器;
- mysql - 连接数据库;
- fs - 文件操作;
- body-parser - 解析post请求体;
- multer - 对
multipart/form-data
编码文件解析;
然后关联两个自定义模块:clear和db,clear中包含了清除所有文件和清除所有缓存的两个方法,db则返回一个数据库连接;1
2var clear = require('./clear');
var db = require('./db');
在当前文件夹创建文件夹uploadFiles,文件下下创建两个子文件夹tmp和file,用来存放临时文件和接收文件。然后设置tmp为临时文件的目录:1
2// 设置文件缓存的目录
var upload = multer({ dest: './uploadFiles/tmp/'});
接着设置应用的请求响应,需要响应四种请求:
app.get('/')
- 首页请求,使用res.sendFile()把首页丢过去;app.post('/upload_file')
- 上传文件请求(见下方解释);app.get('/delete_all_file')
- 删除所有文件请求,调用自定义模块clear中的clearAllFile()
方法,通过返回值来判断是否成功;app.get('/delete_cache')
- 清除缓存请求,调用自定义模块clear中的clearCache()
方法,通过返回值来判断是否成功;
2.1 文件上传详解
响应/upload_file
请求,使用upload.array('file')
为所有接受到的文件添加统一的字段file:
1 | app.post('/upload_file', upload.array('file'), function (req, res) { |
req.files[0]
包含了文件的全部信息(由中间件upload.array(‘file’)写入的),内容如下:1
2
3
4
5
6
7
8
9
10{
fieldname: 'file',
originalname: '542F2294A1566BEA83D1BAE1A00D6C9A.jpg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: './uploadFiles/tmp/',
filename: 'b0dcfcd9d88451bab4ca427571c77cd5',
path: 'uploadFiles\\tmp\\b0dcfcd9d88451bab4ca427571c77cd5',
size: 217804
}
设置文件存储位置,为当前目录uploadFiles文件夹中file字段对应的文件夹,通过设置不同字段对文件进行分类存储可以保证较好的逻辑清晰性:1
var des_file = __dirname + "/uploadFiles/" + req.files[0].fieldname + "/" + req.files[0].originalname;
接下来通过读取编码文件来还原上传的文件,用到的方法如下结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27app.post('/upload_file', upload.array('file'), function (req, res) {
// ....
fs.readFile(req.files[0].path, function (error, data) {
// ....
fs.writeFile(des_file, data, function (err) {
if (err) {
// ....
}else {
// ....
// 删除缓存文件
fs.unlink(req.files[0].path, function(err){
// ....
})
var addSQL = '';
var addSqlParams = [];
// 插入数据
db.connection.query(addSQL, addSqlParams, function (err, result) {
// ....
});
}
});
});
});
2.2 自建模块clear和db
db.js文件结构简单,返回一个数据库连接,使用方法如下:1
2
3
4
5var db = require('./db');
db.connection.query(query1[, query2], callback(err, result){
// ....
})
clear.js文件定义了两个方法:清除缓存和清除所有文件,清除所有文件除了清除磁盘文件外,还清空了数据库中的相关信息:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var clearAllFile = function () {
// 获取目录信息
fs.readdir('./uploadFiles/file', function (error, files) {
// ....
// 循环删除文件
for (var i=0; i<files.length; i++) {
fs.unlink(__dirname + "/uploadFiles/file/" + files[i].toString(), function (err) {
// ....
})
// 在数据库中删除文件信息
var dropSql = '';
db.connection.query(dropSql, function (err, result) {
// ....
})
}
})
return true;
}
// 接口
exports.clearAllFile = clearAllFile;