java處理文件上傳的底層實現

package com.yc.smartupload.util;


import java.util.Arrays;


public class YcFile {
private String fileName; //文件名稱
private String fieldName;  //文件域名
private String fileExt; //文件擴展名
private int fileSize; //文件大小
private String fileType; //文件類型
private byte[] fileByte; //文件數據信息

public YcFile() {
super();
}


public YcFile(String fileName, String fieldName, String fileExt, int fileSize,String fileType,
byte[] fileByte) {
super();
this.fileName = fileName;
this.fieldName = fieldName;
this.fileExt = fileExt;
this.fileSize = fileSize;
this.fileType=fileType;
this.fileByte = fileByte;
}


@Override
public String toString() {
return "YcFile [fileName=" + fileName + ", fieldName=" + fieldName + ", fileExt=" + fileExt + ", fileSize=" + fileSize + ", fileByte=" + Arrays.toString(fileByte) + "]";
}


public String getFileName() {
return fileName;
}


public void setFileName(String fileName) {
this.fileName = fileName;
}


public String getFieldName() {
return fieldName;
}


public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}


public String getFileExt() {
return fileExt;
}


public void setFileExt(String fileExt) {
this.fileExt = fileExt;
}


public int getFileSize() {
return fileSize;
}


public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}


public String getFileType() {
return fileType;
}


public void setFileType(String fileType) {
this.fileType = fileType;
}


public byte[] getFileByte() {
return fileByte;
}


public void setFileByte(byte[] fileByte) {
this.fileByte = fileByte;
}


@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((fieldName == null) ? 0 : fieldName.hashCode());
result = prime * result + Arrays.hashCode(fileByte);
result = prime * result + ((fileExt == null) ? 0 : fileExt.hashCode());
result = prime * result + ((fileName == null) ? 0 : fileName.hashCode());
result = prime * result + fileSize;
result = prime * result + ((fileType == null) ? 0 : fileType.hashCode());
return result;
}


@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
YcFile other = (YcFile) obj;
if (fieldName == null) {
if (other.fieldName != null)
return false;
} else if (!fieldName.equals(other.fieldName))
return false;
if (!Arrays.equals(fileByte, other.fileByte))
return false;
if (fileExt == null) {
if (other.fileExt != null)
return false;
} else if (!fileExt.equals(other.fileExt))
return false;
if (fileName == null) {
if (other.fileName != null)
return false;
} else if (!fileName.equals(other.fileName))
return false;
if (fileSize != other.fileSize)
return false;
if (fileType == null) {
if (other.fileType != null)
return false;
} else if (!fileType.equals(other.fileType))
return false;
return true;
}

}


package com.yc.smartupload.util;


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


import javax.servlet.http.HttpServletRequest;




public class YcUploadUtil {
Map<String,String> parameterMap=new HashMap<String,String>();
private Set<YcFile> files=new HashSet<YcFile>(); //所有文件對象


private int uploadTotalSize=0; //上傳數據的總大小
private byte[] saveUploadFileArray=null; //保存上傳數據的數組


private boolean isEnter = false; //是否是回車鍵
private int currentIndex; //當前數據讀到的位置
private String boundStr=new String(); //邊界信息
private String dataHeader = new String(); //獲取請求頭數據


private int startData; //數據開始的位置
private int endData; //數據結束的位置


private String fieldName = new String(); //上傳數據的name屬性的屬性名
private String fileName = new String(); //上傳文件的文件名
private String fileExt = new String(); //上傳文件的擴展名
private String fileType = new String(); //上次文件的文件類型
boolean isFile = false;


/**
* 獲取請求中的文本參數
* @return
*/
public Map<String,String> getRequestInfo(){
return parameterMap;
}


public Set<YcFile> getFiles() {
return files;
}


public void upload(HttpServletRequest request) throws Exception{
boolean isFile=false;
uploadTotalSize=request.getContentLength();
saveUploadFileArray=new byte[uploadTotalSize];
int readLength=0; //當前讀到的長度
int totalRead=0; //總共讀到的長度


//將請求數據讀到字節數組中
for(totalRead=0;totalRead<uploadTotalSize; totalRead += readLength){
try {
readLength = request.getInputStream().read(saveUploadFileArray, totalRead, uploadTotalSize - totalRead);
} catch (IOException e) {
e.printStackTrace();
}
}


//請求數據的最開始是邊界數據,然後以回車結束,所有先從最前面獲取邊界信息,如:------WebKitFormBoundarycQLwEmu2ssMhXLJ2
for(;!isEnter && currentIndex < uploadTotalSize; currentIndex++){
if(saveUploadFileArray[currentIndex] == 13){//如果是回車,說明第一行邊界數據已經讀完
isEnter = true;
}else{
boundStr = boundStr + (char)saveUploadFileArray[currentIndex];
}
}


if(currentIndex == 1){ //說明不是multipart/form-data類型
return;
}
currentIndex++; //跳過回車
do{
if(currentIndex >= uploadTotalSize){ //如果已經讀完,則跳出循環
//break;
}
dataHeader = getDataHeader();
currentIndex = currentIndex + 2; //跳過回車
isFile = dataHeader.indexOf("filename") > 0;//如果有filename說明是一個文件框,否則就是普通的文本框
fieldName = getDataFieldValue(dataHeader, "name"); //獲取文本框name屬性的屬性名
if(isFile){ //如果是一個文件
fileName = getDataFieldValue(dataHeader, "filename"); //獲取文件名
fileExt = getFileExt(fileName);
fileType = getContentType(dataHeader);
}
getDataPart();
if(isFile && fileName.length() > 0){ 
//允許上傳的文件格式、拒絕上傳的文件格式、文件大小限定等的校驗
}


if(isFile){//保存上傳的文件
YcFile file=new YcFile();
file.setFieldName(fieldName);
file.setFileName(fileName);
file.setFileExt(fileExt);
file.setFileType(fileType);
if(fileType.indexOf("application/x-macbinary") > 0){ //如果是bin文件
startData = startData + 128;
}
int size=(endData-startData)+1;
file.setFileSize(size);
byte[] bt=new byte[size];
System.arraycopy(saveUploadFileArray,startData,bt,0,size);
file.setFileByte(bt);
files.add(file);
} else{ //如果是普通文本框,則讀取數據然後保存到parameterMap中,以字符串的方式返回給用戶
String value = new String(saveUploadFileArray,startData,(endData-startData)+1,"UTF-8");
parameterMap.put(fieldName,value);
}
if((char)saveUploadFileArray[currentIndex + 1] == '-'){ //說明已經是結尾了,以兩個--結尾
break;
}
currentIndex = currentIndex + 2;
} while(true);
}


/**
* 獲取上次文件的文件類型
* @param dataHeader
* @return
*/
private String getContentType(String dataHeader){
String flag="Content-Type:";
String value = new String();
int start = dataHeader.indexOf(flag)+flag.length();
if(start != -1){
value = dataHeader.substring(start+1,dataHeader.length());
}
return value;
}


/**
* 獲取文件的擴展名
* @param fileName
* @return
*/
private String getFileExt(String fileName){
if(fileName == null){
return null;
}
int start = fileName.lastIndexOf('.') ;
if(start>0){
return fileName.substring(start+1,fileName.length());
}else{
return "";
}
}


/**
* 獲取數據部分信息
*/
private void getDataPart(){
int searchPos = currentIndex;
int keyPos = 0;
int boundaryLen = boundStr.length();//邊界長度
startData = currentIndex; //記錄數據開始的位置
endData = 0; //記錄數據結束的位置
do{
if(searchPos >= uploadTotalSize){
break;
}
if(saveUploadFileArray[currentIndex] ==(byte)boundStr.charAt(keyPos)){
if(keyPos==boundaryLen-1){//說明是邊界的最後了
endData = currentIndex-boundaryLen-2; //數據結束的位置爲當前-分割 -\r\n
break;
}
currentIndex++;
keyPos++;
} else{
currentIndex++;
keyPos=0;
}
} while(true);
currentIndex++;
}


/**
* 獲取每個提交數據的請求頭信息,如:Content-Disposition: form-data; name="photo"; filename="3.jpg"
*/
private String getDataHeader(){
int start = currentIndex; //開始讀取請求數據的頭信息的位置
int end = 0; //結束位置
boolean isEnd = false; //是否已經讀完
while(!isEnd){
//如果遇到連續兩個回車,說明第一個數據已經讀完  \r\n 兩個字符
if(saveUploadFileArray[currentIndex] == 13 && saveUploadFileArray[currentIndex + 2] == 13){
isEnd = true;
end = currentIndex;
currentIndex = currentIndex + 2;
} else{
currentIndex++;
}
}
return new String(saveUploadFileArray, start,end-start);
}


/**
* 獲取指定的屬性的屬性值  
* @param dataHeader 數據頭協議字符串:如:Content-Disposition: form-data; name="photo"; filename="3.jpg"
* @param fieldName 要獲取的字段屬性的屬性名
* @return 對應的屬性值
* @throws UnsupportedEncodingException
*/
private String getDataFieldValue(String dataHeader, String fieldName){
//構造標示字符串
String flag=fieldName+"=\""; //如:name->name="
int startPos=dataHeader.indexOf(flag)+flag.length();
if(startPos>0){
return dataHeader.substring(startPos,dataHeader.indexOf("\"",startPos));
}else{
return null;
}
}
}

發佈了70 篇原創文章 · 獲贊 78 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章