java socket上传_Java中用Socket实现HTTP文件上传实例

我想做过web开发的程序员大部分都做过文件上传的功能,大多数时候我们都是借助于commons-fileupload这样的jar包实现的。下面我试着通过读取Socket的输入流来实现一个文件上传的功能。

在做文件上传之前我们需要先了解一下HTTP POST的附件上传协议。HTTP附件上传协议是RFC1876协议,RFC1876协议是在HTTP协议的基础上为INPUT标签增加了file属性,同时限定了Form的method必须为POST,ENCTYPE必须为multipart/form-data。RFC1867协议对HTTP头作了适当地变更,content-type头由以前的:content-type:application/x-www-form-urlencoded变为content-type:multipart/form-data;+空格+boundary=字符串。RFC1867增加了文件上传得功能,而上传文件内容自然也会被加入到HTTP的实体中。现在因为既有HTTP一般的参数实体,又有上传文件的实体,所以用boundary把每种实体进行了分割。具体的看下图:

df32b7e08d2ceb3c3c9822a9e76a56e6.png

接下来就开始我们的代码部分吧。

我在前面的文章中写过创建一个自己的Web服务器,现在我们的重点要放在对socket的输入流的解析中。具体代码如下:

public void parseRequest() {

LineNumberReader br = new LineNumberReader(new InputStreamReader(inputStream));

StringBuffer sb = new StringBuffer();

String str = null;

try {

//读取请求行

String requestLine = br.readLine();

if (!StringUtils.isEmpty(requestLine)) {

sb.append(requestLine);

String[] reqs = requestLine.split(" ");

if (reqs != null && reqs.length > 0) {

if ("GET".equals(reqs[0])) {

method = "GET";

} else {

method = "POST";

}

}

}

//读取请求头

while ((str = br.readLine()) != null) {

if ("".equals(str)) {

break;

}

if (!StringUtils.isEmpty(str)) {

if (str.indexOf(":") > 0) {

String[] strs = str.split(":");

headers.put(strs[0].toLowerCase(), strs[1].trim());

}

}

sb.append(str).append("\n");

}

//POST请求,Content-type为 multipart/form-data

String contentType = null;

if ("POST".equals(method) && ((contentType = headers.get("content-type")) != null

&& headers.get("content-type").startsWith("multipart/form-data"))) {

//文件上传的分割位 这里只处理单个文件的上传

String boundary = contentType.substring(contentType.indexOf("boundary") +

"boundary=".length());

//解析消息体

while ((str = br.readLine()) != null) {

//解析结束的标记

do {

//读取boundary中的内容

//读取Content-Disposition

str = br.readLine();

//说明是文件上传

if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) {

str = str.substring("Content-Disposition:".length());

String[] strs = str.split(";");

String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1];

System.out.println("fileName = " + fileName);

//这一行是Content-Type

br.readLine();

//这一行是换行

br.readLine();

//正式去读文件的内容

BufferedWriter bw = null;

try {

bw = new BufferedWriter(new OutputStreamWriter(new

FileOutputStream("G:\\LearnVideo\\fileLoad" +

File.separator + fileName), "UTF-8"));

while (true) {

str = br.readLine();

if (str.startsWith("--" + boundary)) {

break;

}

bw.write(str);

bw.newLine();

}

bw.flush();

} catch (Exception e) {

} finally {

if (bw != null) {

bw.close();

}

}

}

if (str.indexOf("Content-Disposition:") >= 0) {

str = str.substring("Content-Disposition:".length());

String[] strs = str.split(";");

String name = strs[strs.length - 1].replace("\"", "").split("=")[1];

br.readLine();

StringBuilder stringBuilder = new StringBuilder();

while (true) {

str = br.readLine();

if (str.startsWith("--" + boundary)) {

break;

}

stringBuilder.append(str);

}

parameters.put(name, stringBuilder.toString());

}

} while (("--" + boundary).equals(str));

//解析结束

if (str.equals("--" + boundary + "--")) {

break;

}

}

}

//System.out.println(sb.toString());

//获取URI

uri = StringUtils.parserUri(sb.toString(), " ");

int flag = -1;

//说明有参数

if ((flag = uri.indexOf('?')) >= 0) {

String oldUri = uri;

uri = uri.substring(0,flag);

String parameterPath = oldUri.substring(flag+1);

String[] parameter = parameterPath.split("&");

if (parameter != null && parameter.length > 0) {

for (int i = 0; i < parameter.length; i++) {

String str1 = parameter[i];

if((flag = str1.indexOf('=')) >= 0){

String key = str1.substring(0,flag);

String value = str1.substring(flag+1);

parameters.put(key,value);

}else{

parameters.put(str,null);

}

}

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

我们启动自己创建的Web服务器,然后在浏览器中输入:http://localhost:8004/static/uploadPage.html,页面如下:

f9588e1362670281bc83e155c4af1663.png

选择我们要上次的文件,然后点击上传按钮,我们会发现我们的功能已经被上传到G:\LearnVideo\fileLoad这个目录下了。示例如下:

3e7dff3e27e31faba98a2e548ecc2855.gif

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值