实际本机测试上传一个717MB的文件,用时342秒
实际局域网测试上传一个717MB的文件,用时685秒
上传用HTML
<form action="http:\\localhost:8080" method="post" enctype="multipart/form-data">
<input type="file" name="file01"/>
重命名为<input type="text" name="newname01" maxlength="36"/>(不更名,则此处为空)<br/>
<input type="file" name="file02"/>
重命名为<input type="text" name="newname02" maxlength="36"/>(不更名,则此处为空)<br/>
<input type="file" name="file03"/>
重命名为<input type="text" name="newname03" maxlength="36"/>(不更名,则此处为空)<br/>
<input type="file" name="file04"/>
重命名为<input type="text" name="newname04" maxlength="36"/>(不更名,则此处为空)<br/>
<input type="file" name="file05"/>
重命名为<input type="text" name="newname05" maxlength="36"/>(不更名,则此处为空)<br/>
<input type="reset" value="清空表单"><input type="submit" value="开始上传"/>
</form>
JAVA源程序
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
public class UploadSeverOnly extends JFrame{
private static final long serialVersionUID = -4475518387898285372L;
private static final long DEF_ONE_THREAD_MAX_TIME = 10*60*1000;
private static final int DEF_MAX_FILE_COUNT = 5;
private static final String DEF_FILE_PATH = "F:\\upload\\";
private static final int DEF_PORT = 8080;
private static final byte[] LINE_BREAK = {0x0D, 0x0A};
private static final byte[] BLOCK_BREAK = {0x0D, 0x0A, 0x0D, 0x0A};
private static final int[] LINE_BREAK_NEXT = new int[LINE_BREAK.length];
private static final int[] BLOCK_BREAK_NEXT = new int[BLOCK_BREAK.length];
private static final byte[] CONTENT_TYPE_FORMDATA = " multipart/form-data".getBytes();
private static final byte[] BOUNDARY = " boundary=".getBytes();
private static final byte[] CONTENT_LENGTH = "Content-Length:".getBytes();
private static final byte[] CD_NAME_END = "\"".getBytes();//Content-Disposition: form-data; name="file01"; filename="E:\01.txt"
private static final byte[] NAME = " name=\"".getBytes();
private static final byte[] FILE_NAME = " filename=\"".getBytes();
private static final int[] CONTENT_TYPE_FORMDATA_NEXT = new int[CONTENT_TYPE_FORMDATA.length];
private static final int[] BOUNDARY_NEXT = new int[BOUNDARY.length];
private static final int[] CONTENT_LENGTH_NEXT = new int[CONTENT_LENGTH.length];
private static final int[] FILE_NAME_NEXT = new int[FILE_NAME.length];
private static final int[] CD_NAME_END_NEXT = new int[CD_NAME_END.length];
private static final int[] NAME_NEXT = new int[NAME.length];
private int port_ = DEF_PORT;
private String filePath_ = DEF_FILE_PATH;
private long oneThreadMaxTime_ = DEF_ONE_THREAD_MAX_TIME;//超时时间
private int maxFileCount_ = DEF_MAX_FILE_COUNT;//每次最大上传文件数
private JTextArea textarea_ = new JTextArea();
private JTextField portField_ = new JTextField(Integer.toString(DEF_PORT), 5);
private JTextField threadMaxTimeField_ = new JTextField(Long.toString(DEF_ONE_THREAD_MAX_TIME), 10);
private JTextField maxFileCountField_ = new JTextField(Long.toString(DEF_MAX_FILE_COUNT), 3);
private JTextField serverPathField_ = new JTextField(DEF_FILE_PATH, 20);
private JButton chooseFileBT_ = new JButton("Select");
private File choosingPath_ = new File(DEF_FILE_PATH);
private JButton startbt_ = new JButton("Start");
private JButton stopbt_ = new JButton("Stop");
private ServerSocket serverSocket_ = null;
boolean isStart_ = false;
static {
getKMPnext(LINE_BREAK, LINE_BREAK_NEXT);
getKMPnext(BLOCK_BREAK, BLOCK_BREAK_NEXT);
getKMPnext(CONTENT_TYPE_FORMDATA, CONTENT_TYPE_FORMDATA_NEXT);
getKMPnext(BOUNDARY, BOUNDARY_NEXT);
getKMPnext(CONTENT_LENGTH, CONTENT_LENGTH_NEXT);
getKMPnext(CD_NAME_END, CD_NAME_END_NEXT);
getKMPnext(NAME, NAME_NEXT);
getKMPnext(FILE_NAME, FILE_NAME_NEXT);
}
public UploadSeverOnly() {
super("Upload Server");
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
portField_.setText(Integer.toString(DEF_PORT));
threadMaxTimeField_.setText(Long.toString(DEF_ONE_THREAD_MAX_TIME));
maxFileCountField_.setText(Integer.toString(DEF_MAX_FILE_COUNT));
serverPathField_.setText(DEF_FILE_PATH);
JPanel panelTop = new JPanel();
panelTop.setLayout(new BoxLayout(panelTop, BoxLayout.Y_AXIS));
Dimension btsize = new Dimension(80, 21);
chooseFileBT_.setPreferredSize(btsize);
startbt_.setPreferredSize(btsize);
stopbt_.setPreferredSize(btsize);
JPanel panelup = new JPanel();
panelup.add(new JLabel("Port"));
panelup.add(portField_);
JPanel panelPath = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
panelPath.add(new JLabel("Path"));
panelPath.add(serverPathField_);
panelPath.add(chooseFileBT_);
panelup.add(panelPath);
panelTop.add(panelup);
JPanel paneldown = new JPanel();
paneldown.add(new JLabel("MaxTime"));
paneldown.add(threadMaxTimeField_);
paneldown.add(new JLabel("MaxFile"));
paneldown.add(maxFileCountField_);
paneldown.add(startbt_);
paneldown.add(stopbt_);
panelTop.add(paneldown);
stopbt_.setEnabled(false);
mainPanel.add(panelTop, BorderLayout.NORTH);
mainPanel.add(new JScrollPane(textarea_), BorderLayout.CENTER);
getContentPane().add(mainPanel);
setSize(600, 600);
// pack();
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
}
});
addListeners();
}
private void setComponentEnabled(boolean enabled) {
isStart_ = !enabled;
portField_.setEnabled(enabled);
startbt_.setEnabled(enabled);
stopbt_.setEnabled(!enabled);
threadMaxTimeField_.setEnabled(enabled);
maxFileCountField_.setEnabled(enabled);
serverPathField_.setEnabled(enabled);
chooseFileBT_.setEnabled(enabled);
}
private void addListeners() {
chooseFileBT_.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser(choosingPath_);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setDialogTitle("请选择一个文件");
fileChooser.setVisible(true);
if (fileChooser.showOpenDialog(UploadSeverOnly.this) == JFileChooser.APPROVE_OPTION) {
choosingPath_ = fileChooser.getCurrentDirectory();
serverPathField_.setText(fileChooser.getSelectedFile().getAbsolutePath());
}
}
});
startbt_.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
new Thread(){
public void run() {
startBtAction();
}
}.start();
}
});
stopbt_.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
try {
serverSocket_.close();
} catch (Exception exp) {
isStart_ = false;
error(exp);
}
setComponentEnabled(true);
}
});
}
private void startBtAction() {
try {
try {
filePath_ = serverPathField_.getText();
File filePathFile = new File(filePath_);
if (!filePathFile.exists()) {
if (!filePathFile.mkdirs()) {
throw new Exception("Can'n make dirs: " + filePathFile.getAbsolutePath());
}
}
serverPathField_.setText(filePathFile.getAbsolutePath());
} catch (Exception exp) {
filePath_ = DEF_FILE_PATH;
serverPathField_.setText(filePath_);
try {
if (new File(filePath_).exists() || !new File(filePath_).mkdirs()) {
throw new Exception("Can'n make dirs: " + filePath_);
}
} catch (Exception expA) {
filePath_ = System.getProperty("user.home");
serverPathField_.setText(filePath_);
}
}
choosingPath_ = new File(filePath_);
try {
oneThreadMaxTime_ = Long.parseLong(threadMaxTimeField_.getText());
} catch (Exception exp) {
oneThreadMaxTime_ = DEF_ONE_THREAD_MAX_TIME;
threadMaxTimeField_.setText(Long.toString(oneThreadMaxTime_));
}
try {
maxFileCount_ = Integer.parseInt(maxFileCountField_.getText());
} catch (Exception exp) {
maxFileCount_ = DEF_MAX_FILE_COUNT;
maxFileCountField_.setText(Integer.toString(maxFileCount_));
}
try {
port_ = Integer.parseInt(portField_.getText());
} catch (Exception exp) {
port_ = DEF_PORT;
portField_.setText(Integer.toString(port_));
}
serverSocket_ = new ServerSocket(port_);//Integer.parseInt(argv[0]));
setComponentEnabled(false);
while (isStart_)
new ListenOneThread(serverSocket_.accept()).start();
} catch (Exception exp) {
isStart_ = false;
error(exp);
}
}
class ListenOneThread extends Thread {
Socket client;
ListenOneThread(Socket client) throws SocketException {
this.client = client;
// setPriority(NORM_PRIORITY - 1);
}
public void run() {
long starttime = System.currentTimeMillis();
int fileCount = 0;
int renameCount = 0;
File[] files = new File[maxFileCount_];
String[] newNames = new String[maxFileCount_];
OutputStream outputToClient = null;
InputStream inputFromClient = null;
boolean isFormData = false;
boolean isTimeOut = false;
try {
{
inputFromClient = client.getInputStream();
outputToClient = client.getOutputStream();
int len = 0;
byte[] inBuf = new byte[10 * 1024 * 1024];//此处不能大于4G
int iInBufLow = 0;//inBuf有效数据的起始位置
int inBufMinLeave = 512 * 1024;//如果inBuf尾部有效空间小于此,那么把有效数据拷到inBuf的头部
boolean isHeadOK = false;
long leaveLen = 1;//还剩余多少未接受的数据
int iInBufTop = 0;
byte[] boundaryBytes = new byte[0];
int[] boundaryBytesNext = new int[0];
boolean needReadNewFileName = false;
String fileName = "";
String name = null;
FileOutputStream outStream = null;
boolean needFindBoundary = true;
while(isStart_) {
if (leaveLen <= 0) {
break;
}
if (System.currentTimeMillis() - starttime > oneThreadMaxTime_) {
error(new Exception("Time Out!"));
isTimeOut = true;
break;
}
//如果有效数据尾部之后剩余有效空间小于inBufMinLeave, 把有效数据拷贝到inBuf头部
if (isHeadOK && (inBuf.length - iInBufTop) < inBufMinLeave) {
iInBufTop -= iInBufLow;
System.arraycopy(inBuf, iInBufLow, inBuf, 0, iInBufTop);
iInBufLow = 0;
}
if ((len = inputFromClient.read(inBuf, iInBufTop, inBuf.length - iInBufTop)) > 0) {
iInBufTop += len;
if (!isHeadOK) {
int iHeadEnd;
//此处可以加速,在fromIndex可以改(基本上不用改,一次应该可以读完头)
if ((iHeadEnd = getIndexKMP(inBuf, BLOCK_BREAK, BLOCK_BREAK_NEXT, iInBufLow, iInBufTop - 1)) > 0) {
isHeadOK = true;
//计算Content-Length
int from = getIndexKMP(inBuf, CONTENT_LENGTH, CONTENT_LENGTH_NEXT, iInBufLow, iHeadEnd - 1) + CONTENT_LENGTH.length;
int to = getIndexKMP(inBuf, LINE_BREAK, LINE_BREAK_NEXT, from, iHeadEnd + LINE_BREAK.length);
leaveLen = Long.parseLong(new String(inBuf, from, to - from).trim());
leaveLen -= len - (iHeadEnd + BLOCK_BREAK.length - iInBufLow);
//如果是multipart/form-data, 计算boundary串
int formdataIndex = getIndexKMP(inBuf, CONTENT_TYPE_FORMDATA, CONTENT_TYPE_FORMDATA_NEXT, iInBufLow, iHeadEnd - 1);
from = getIndexKMP(inBuf, BOUNDARY, BOUNDARY_NEXT, iInBufLow, iHeadEnd - 1);
if (formdataIndex >= iInBufLow && from >= iInBufLow) {
isFormData = true;
from += BOUNDARY.length;
to = getIndexKMP(inBuf, LINE_BREAK, LINE_BREAK_NEXT, from, iHeadEnd + LINE_BREAK.length);
boundaryBytes = new byte[to - from + 2];
System.arraycopy(inBuf, from, boundaryBytes, 2, boundaryBytes.length - 2);
boundaryBytes[0] = boundaryBytes[1] = '-';
boundaryBytesNext = new int[boundaryBytes.length];
getKMPnext(boundaryBytes, boundaryBytesNext);
}
//在TextArea中追加头部
iHeadEnd += BLOCK_BREAK.length;
addBytesToArea(textarea_, inBuf, iInBufLow, iHeadEnd - iInBufLow);
iInBufLow = iHeadEnd;
}
if (isHeadOK && leaveLen <= 0) {//isHeaderOK==true后,bodyLen开始生效,当bodyLen小等于0时,此时不需要读,继续处理即可
len = 0;//在上面己处理
} else {
continue;
}
}
leaveLen -= len;
if (isFormData) {
int boundaryIndex;
while(true) {
if (needFindBoundary) {
boundaryIndex = getIndexKMP(inBuf, boundaryBytes, boundaryBytesNext, iInBufLow, iInBufTop - 1);
if (boundaryIndex < 0) {
if (leaveLen > 0 && outStream != null) {
outStream.write(inBuf, iInBufLow, iInBufTop - iInBufLow - boundaryBytes.length);
outStream.flush();
iInBufLow = iInBufTop - boundaryBytes.length;
}
break;
}
needFindBoundary = false;
if (outStream != null) {
//写余下的部分到文件
outStream.write(inBuf, iInBufLow, boundaryIndex - iInBufLow - LINE_BREAK.length);
outStream.flush();
outStream.close();
outStream = null;
} else if(name != null) {
addBytesToArea(textarea_, inBuf, iInBufLow, boundaryIndex - iInBufLow);
if (needReadNewFileName && renameCount < maxFileCount_) {
newNames[renameCount++] = new String(inBuf, iInBufLow, boundaryIndex - iInBufLow - LINE_BREAK.length);
//System.out.println("newName" + renameCount + ": " + newNames[renameCount - 1]);
}
name = null;
}
//达到最后一个分界线处
if (leaveLen <= 0 && (iInBufTop - (boundaryIndex + boundaryBytes.length)) <= boundaryBytes.length) {
addBytesToArea(textarea_, inBuf, boundaryIndex, iInBufTop - boundaryIndex);
iInBufTop = iInBufLow = 0;
break;
}
//移动开始指针到块分界线后面
iInBufLow = boundaryIndex + boundaryBytes.length;
} else {
int blockBreakIndex = getIndexKMP(inBuf, BLOCK_BREAK, BLOCK_BREAK_NEXT, iInBufLow, iInBufTop - 1);
if (blockBreakIndex >= 0) {
if (!needFindBoundary) {//刚过Boundary, 先把name与文件流置空
name = null;
outStream = null;
}
needFindBoundary = true;
addBytesToArea(textarea_, boundaryBytes);
addBytesToArea(textarea_, inBuf, iInBufLow, blockBreakIndex + BLOCK_BREAK.length - iInBufLow);
int nameIndex = getIndexKMP(inBuf, NAME, NAME_NEXT, iInBufLow, blockBreakIndex - 1);
nameIndex += NAME.length;
int afterNameIndex = getIndexKMP(inBuf, CD_NAME_END, CD_NAME_END_NEXT,
nameIndex, blockBreakIndex - 1);
name = new String(inBuf, nameIndex, afterNameIndex - nameIndex);
int fileNameIndex = getIndexKMP(inBuf, FILE_NAME, FILE_NAME_NEXT, iInBufLow, blockBreakIndex - 1);
if (fileNameIndex >= 0) {//此时,流中接下来的内容是一个文件
needReadNewFileName = false;
fileNameIndex += FILE_NAME.length;
int afterFileNameIndex = getIndexKMP(inBuf, CD_NAME_END, CD_NAME_END_NEXT,
fileNameIndex, blockBreakIndex - 1);
fileName = new String(inBuf, fileNameIndex, afterFileNameIndex - fileNameIndex);
if (fileName.indexOf("\\") >= 0) {
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
}
if (fileName.indexOf("/") >= 0) {
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
}
if (fileCount >= maxFileCount_) {
outputToClient.write(("One time can upload max " + maxFileCount_ + " files.\n").getBytes());
} else if (fileName.trim().equals("")) {
addBytesToArea(textarea_, ("User Upload File -> " + "not select file here").getBytes());
} else {
File file = new File(filePath_, getFileName(fileName));
file.createNewFile();
outStream = new FileOutputStream(file);
addBytesToArea(textarea_, ("User Upload File -> " + file.getAbsolutePath()).getBytes());
files[fileCount++] = file;
//System.out.println("file" + fileCount + ": " + file.getName());
}
addBytesToArea(textarea_, LINE_BREAK);
} else {//此时,流中接下来的内容只是要改成的文件名
fileName = null;
needReadNewFileName = true;
//改名待写
}
iInBufLow = blockBreakIndex + BLOCK_BREAK.length;
} else {
break;
}
}
}
} else {
if (inBuf != null) {
addBytesToArea(textarea_, inBuf, iInBufLow, iInBufTop - iInBufLow);
iInBufLow = iInBufTop;
}
if (leaveLen <= 0) {
break;
}
}
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (isTimeOut) {
outputToClient.write("<br>/*<br>Time Out!<br>*/<br> ".getBytes());
} else {
outputToClient.write("<br>/*<br>Server has received your data.<br>*/<br>".getBytes());
}
}
} catch (IOException e) {
error(e);
} finally {
if (isFormData) {
String info = "\n";
for (int i = 0; i < files.length; i++) {//重命名操作
if (files[i] != null && files[i].exists() && files[i].length() <= 0) {//删除0大小文件
info += "\nDELETE: " + files[i].getName() + " is not exist or ZERO LENGTH, do it was deleted.\n";
continue;
}
if (files[i] != null && files[i].exists() && newNames[i] != null && !newNames[i].trim().equals("")) {
String newFileName = getFileName(newNames[i]);
if (!newFileName.equals(newNames[i])) {
info += "\nEXISTS: You want to rename to " + newNames[i] + ", but it is exits.";
}
info += "\nRENAME: " + files[i].getName() + " renameto " + newFileName + "\n";
files[i].renameTo(new File(filePath_ + newFileName));
}
}
long timespan = System.currentTimeMillis() - starttime;
info += "Total Time: " + timespan / 3600000 + ":" + timespan / 60000 % 60 + ":" + timespan / 1000 % 60
+ " " + timespan % 1000 + "<br>";
textarea_.append("\n/*\n" + info + "\n*/\n");
if (outputToClient != null) {
try {
outputToClient.write(info.replace("\n", "<br>").getBytes());
} catch (IOException expOutPut) {
error(expOutPut);
}
}
}
if (outputToClient != null) {
try {
outputToClient.write('\0');
outputToClient.flush();
outputToClient.close();
System.out.println("Close");
} catch (IOException expCloseOutPut) {
error(expCloseOutPut);
}
}
try {
client.close();
client = null;
} catch (IOException expClientClose) {
error(expClientClose);
}
}
}
}
private void addBytesToArea(JTextArea textArea, byte[] bytes) {
addBytesToArea(textArea, bytes, 0);
}
private void addBytesToArea(JTextArea textArea, byte[] bytes, int from) {
addBytesToArea(textArea, bytes, from, bytes.length - from);
}
private void addBytesToArea(JTextArea textArea, byte[] bytes, int from, int len) {
// //Next for not support multi laguage.
// for (int i = from; i < from + len; i++) {
// textArea.append((char)(bytes[i] & 0xFFFF) + "");
// }
textArea.append(new String(bytes, from, len));
}
private void error(Exception e) {
textarea_.append("\n/*\n" + e.toString() + "\n*/\n");
if (isStart_) {
return;
}
if (serverSocket_ != null) {
try {
serverSocket_.close();
} catch (Exception expCloseSocket) {
expCloseSocket.printStackTrace();
}
}
setComponentEnabled(true);
}
private String getFileName(String fileName) {
File newNameFile = new File(filePath_ + fileName);
String newFileName = fileName;
if (newNameFile.exists()) {
int nameIndex = 1;
String[] newNameSplit = null;
int index = -1;
if ((index = fileName.indexOf('.')) >= 0) {
newNameSplit = new String[2];
newNameSplit[0] = fileName.substring(0, index);
newNameSplit[1] = fileName.substring(index);
}
while (newNameFile.exists()) {
newFileName = newNameSplit == null ? (fileName + "_" + nameIndex)
: (newNameSplit[0] + "_" + nameIndex + newNameSplit[1]);
newNameFile = new File(filePath_ + newFileName);
++nameIndex;
}
}
return newFileName;
}
public static int getIndexKMP(byte[] bytesMu, byte[] bytesZi, int[] next) {
return getIndexKMP(bytesMu, bytesZi, next, 0);
}
public static int getIndexKMP(byte[] bytesMu, byte[] bytesZi, int[] next, int from) {
return getIndexKMP(bytesMu, bytesZi, next, from, bytesMu.length - 1);
}
public static int getIndexKMP(byte[] bytesMu, byte[] bytesZi, int[] next, int from, int to) {
int i = from;
int j = 0;
int maxIndex = to < 0 ? bytesMu.length : (to + 1);
while (i < maxIndex && j < bytesZi.length) {
if (j == -1 || bytesMu[i] == bytesZi[j]) {
++i;
++j;
} else {
j = next[j];
}
}
if (j >= bytesZi.length) {
return i - bytesZi.length;
}
return -1;
}
public static void getKMPnext(byte[] bytes, int[] next) {
int i = 0;
int j = -1;
next[0] = -1;
int len = bytes.length - 1;
while (i < len) {
if (j == -1 || bytes[i] == bytes[j]) {
++i;
++j;
next[i] = j;
} else {
j = next[j];
}
}
getKMPnextVal(bytes, next);
}
public static void getKMPnextVal(byte[] bytes, int[] nextVal) {
int i = 0;
int j = -1;
nextVal[i] = -1;
int len = bytes.length - 1;
while (i < len) {
if (j == -1 || bytes[i] == bytes[j]) {
++i;
++j;
if (bytes[i] != bytes[j]) {
nextVal[i] = j;
} else {
nextVal[i] = nextVal[j];
}
} else {
j = nextVal[j];
}
}
}
public static void main(String[] args) {
new UploadSeverOnly().setVisible(true);
}
}
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
30 | 31 | 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 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
导航
统计
- 随笔: 115
- 文章: 1
- 评论: 86
- 引用: 0
常用链接
留言簿(5)
随笔档案(115)
网址
搜索
积分与排名
最新评论
阅读排行榜
评论排行榜
|
|