0%

文件上传与魔数

问题的出现

今天在测试图片上传的时候,工作电脑中没有现成的图片(其实是懒得找),又不想去网上下载就把word文档改了后缀名(.jpeg)上传,没想到上传失败。

心里头非常纳闷,第一反应是代码有BUG,打开项目的过程中,不对。我把文件后缀名重新改回在上传文件,可以正常上传了。

定位问题

由此,问题已经定位了,是我的这个不正常行为引起的。但为什么会出现这个问题,打开搜索引擎一通猛搜。

原来是有一个叫做 magic number 的东西,文件的起始几个字节的内容是固定的,这几个字节的内容也被称为 magic number, 因此可以根据这几个字节的内容确定文件类型。

解决方案

常见的文件类型的魔数

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
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
public enum FileType {
/**
* JPEG
*/
JPEG("JPEG", "FFD8FF"),

/**
* PNG
*/
PNG("PNG", "89504E47"),

/**
* GIF
*/
GIF("GIF", "47494638"),

/**
* TIFF
*/
TIFF("TIFF", "49492A00"),

/**
* Windows bitmap
*/
BMP("BMP", "424D"),

/**
* CAD
*/
DWG("DWG", "41433130"),

/**
* Adobe photoshop
*/
PSD("PSD", "38425053"),

/**
* Rich Text Format
*/
RTF("RTF", "7B5C727466"),

/**
* XML
*/
XML("XML", "3C3F786D6C"),

/**
* HTML
*/
HTML("HTML", "68746D6C3E"),

/**
* Outlook Express
*/
DBX("DBX", "CFAD12FEC5FD746F "),

/**
* Outlook
*/
PST("PST", "2142444E"),

/**
* doc;xls;dot;ppt;xla;ppa;pps;pot;msi;sdw;db
*/
OLE2("OLE2", "0xD0CF11E0A1B11AE1"),

/**
* Microsoft Word/Excel
*/
XLS_DOC("XLS_DOC", "D0CF11E0"),

/**
* Microsoft Access
*/
MDB("MDB", "5374616E64617264204A"),

/**
* Word Perfect
*/
WPB("WPB", "FF575043"),

/**
* Postscript
*/
EPS_PS("EPS_PS", "252150532D41646F6265"),

/**
* Adobe Acrobat
*/
PDF("PDF", "255044462D312E"),

/**
* Windows Password
*/
PWL("PWL", "E3828596"),

/**
* ZIP Archive
*/
ZIP("ZIP", "504B0304"),

/**
* ARAR Archive
*/
RAR("RAR", "52617221"),

/**
* WAVE
*/
WAV("WAV", "57415645"),

/**
* AVI
*/
AVI("AVI", "41564920"),

/**
* Real Audio
*/
RAM("RAM", "2E7261FD"),

/**
* Real Media
*/
RM("RM", "2E524D46"),

/**
* Quicktime
*/
MOV("MOV", "6D6F6F76"),

/**
* Windows Media
*/
ASF("ASF", "3026B2758E66CF11"),

/**
* MIDI
*/
MID("MID", "4D546864");

private String key;
private String value;

FileType(String key, String value) {
this.key = key;
this.value = value;
}

public String getValue() {
return value;
}
public String getKey() {
return key;
}
}

具体的实现就是根据文件的魔数判断文件的真实类型

文件工具类

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
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
public class FileUtil {

/**
* 获取文件投
*
* @param filePath 文件路径
* @return 16 进制的文件投信息
* @throws IOException
*/
private static String getFileHeader(String filePath) throws IOException {
byte[] b = new byte[28];
InputStream inputStream = new FileInputStream(filePath);
inputStream.read(b, 0, 28);
inputStream.close();
return bytes2hex(b);
}

/**
* 将字节数组转换成16进制字符串
*/
private static String bytes2hex(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (byte b : src) {
int v = b & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}

/**
* 根据文件路径获取文件类型
*
* @param filePath 文件路径
* @return 文件类型
* @throws IOException
*/
public static FileType getFileType(String filePath) throws IOException {
String fileHead = getFileHeader(filePath);
if (null == fileHead || fileHead.length() == 0) {
return null;
}
fileHead = fileHead.toUpperCase();
FileType[] fileTypes = FileType.values();
for (FileType type : fileTypes) {
if (fileHead.startsWith(type.getValue())) {
return type;
}
}
return null;
}
}

总结

没想到这个被有意无意忽视的问题就这样出现在我的面前,真是意料之外,又在情理之中。

考虑一个问题,还是得想的多一点。