MultipartStream.java
上传用户:u_thks
上传日期:2022-07-31
资源大小:1910k
文件大小:17k
源码类别:
WEB源码(ASP,PHP,...)
开发平台:
Java
- package com.gamvan.fileUpload;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.UnsupportedEncodingException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import com.gamvan.tools.TypeChange;
- public class MultipartStream{
- /**
- * 取当前读取进度
- */
- private long readsBytes = 0;
- /**
- * The maximum length of <code>header-part</code> that will be
- * processed (10 kilobytes = 10240 bytes.).
- */
- public static final int HEADER_PART_SIZE_MAX = 10240;
- /**
- * The default length of the buffer used for processing a request.
- */
- protected static final int DEFAULT_BUFSIZE = 4096;
- /**
- * A byte sequence that marks the end of <code>header-part</code>
- * (<code>CRLFCRLF</code>).
- */
- protected static final byte[] HEADER_SEPARATOR = {0x0D, 0x0A, 0x0D, 0x0A};
- /**
- * A byte sequence that that follows a delimiter that will be
- * followed by an encapsulation (<code>CRLF</code>).
- */
- protected static final byte[] FIELD_SEPARATOR = { 0x0D, 0x0A };
- /**
- * A byte sequence that that follows a delimiter of the last
- * encapsulation in the stream (<code>--</code>).
- */
- protected static final byte[] STREAM_TERMINATOR = { 0x2D, 0x2D };
- /**
- * The input stream from which data is read.
- */
- private InputStream input;
- /**
- * The length of the boundary token plus the leading <code>CRLF--</code>.
- */
- private int boundaryLength;
- /**
- * The amount of data, in bytes, that must be kept in the buffer in order
- * to detect delimiters reliably.
- */
- private int keepRegion;
- /**
- * The byte sequence that partitions the stream.
- */
- private byte[] boundary;
- /**
- * The length of the buffer used for processing the request.
- */
- private int bufSize;
- /**
- * The buffer used for processing the request.
- */
- private byte[] buffer;
- /**
- * The index of first valid character in the buffer.
- * <br>
- * 0 <= head < bufSize
- */
- private int head;
- /**
- * The index of last valid characer in the buffer + 1.
- * <br>
- * 0 <= tail <= bufSize
- */
- private int tail;
- /**
- * The content encoding to use when reading headers.
- */
- private String headerEncoding;
- /**
- * Default constructor.
- *
- * @see #MultipartStream(InputStream, byte[], int)
- * @see #MultipartStream(InputStream, byte[])
- *
- */
- public MultipartStream()
- {
- }
- public MultipartStream(InputStream input, byte[] boundary,int bufSize){
- this.input = input;
- this.bufSize = bufSize;
- this.buffer = new byte[bufSize];
- // We prepend CR/LF to the boundary to chop trailng CR/LF from
- // body-data tokens.
- this.boundary = new byte[boundary.length + 4];
- this.boundaryLength = boundary.length + 4;
- this.keepRegion = boundary.length + 3;
- this.boundary[0] = 0x0D;
- this.boundary[1] = 0x0A;
- this.boundary[2] = 0x2D;
- this.boundary[3] = 0x2D;
- System.arraycopy(boundary, 0, this.boundary, 4, boundary.length);
- head = 0;
- tail = 0;
- }
- public MultipartStream(InputStream input, byte[] boundary) throws IOException{
- this(input, boundary, DEFAULT_BUFSIZE);
- }
- public String getHeaderEncoding(){
- return headerEncoding;
- }
- public void setHeaderEncoding(String encoding){
- headerEncoding = encoding;
- }
- public byte readByte() throws IOException{
- // Buffer depleted ?
- if (head == tail){
- head = 0;
- // Refill.
- tail = input.read(buffer, head, bufSize);
- if (tail == -1){
- // No more data available.
- throw new IOException("No more data is available");
- }
- }
- return buffer[head++];
- }
- /**
- *
- * @return
- * @throws MalformedStreamException
- */
- public boolean readBoundary() throws MalformedStreamException{
- byte[] marker = new byte[2];
- boolean nextChunk = false;
- head += boundaryLength;
- try{
- marker[0] = readByte();
- marker[1] = readByte();
- if (arrayequals(marker, STREAM_TERMINATOR, 2)){
- nextChunk = false;
- }else if (arrayequals(marker, FIELD_SEPARATOR, 2)){
- nextChunk = true;
- }else{
- throw new MalformedStreamException(
- "Unexpected characters follow a boundary");
- }
- }
- catch (IOException e)
- {
- throw new MalformedStreamException("Stream ended unexpectedly");
- }
- return nextChunk;
- }
- public void setBoundary(byte[] boundary) //设置边界
- throws IllegalBoundaryException
- {
- if (boundary.length != boundaryLength - 4){
- throw new IllegalBoundaryException("The length of a boundary token can not be changed");
- }
- System.arraycopy(boundary, 0, this.boundary, 4, boundary.length);
- }
- /*
- *
- *
- *
- */
- public String readHeaders() throws MalformedStreamException{
- int i = 0;
- byte b[] = new byte[1];
- // to support multi-byte characters
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int sizeMax = HEADER_PART_SIZE_MAX;
- int size = 0;
- while (i < 4){
- try{
- b[0] = readByte();
- }catch (IOException e){
- throw new MalformedStreamException("Stream ended unexpectedly");
- }
- size++; //当前读取字节数
- readsBytes += size; //读取进度
- if (b[0] == HEADER_SEPARATOR[i]){
- i++;
- }else{
- i = 0;
- }
- if (size <= sizeMax){
- baos.write(b[0]);
- }
- }
- String headers = null;
- if (headerEncoding != null){
- try{
- headers = baos.toString(headerEncoding);
- }catch (UnsupportedEncodingException e){
- // Fall back to platform default if specified encoding is not
- // supported.
- headers = baos.toString();
- }
- }else{
- headers = baos.toString();
- }
- return headers;
- }
- public int readBodyData(OutputStream output,HttpServletRequest req) throws MalformedStreamException, IOException{
- boolean done = false;
- int pad;
- int pos;
- int bytesRead;
- int total = 0;
- HttpSession session = req.getSession();
- while (!done)
- {
- // Is boundary token present somewere in the buffer?
- pos = findSeparator();
- if (pos != -1)
- {
- // Write the rest of the data before the boundary.
- output.write(buffer, head, pos - head);
- total += pos - head;
- head = pos;
- done = true;
- }
- else
- {
- // Determine how much data should be kept in the
- // buffer.
- if (tail - head > keepRegion)
- {
- pad = keepRegion;
- }
- else
- {
- pad = tail - head;
- }
- // Write out the data belonging to the body-data.
- output.write(buffer, head, tail - head - pad);
- // Move the data to the beging of the buffer.
- total += tail - head - pad;
- System.arraycopy(buffer, tail - pad, buffer, 0, pad);
- //if(readsBytes==0)
- //readsBytes = total; //当前读取的字节数。
- // Refill buffer with new data.
- head = 0;
- bytesRead = input.read(buffer, pad, bufSize - pad);
- if (bytesRead != -1)
- {
- tail = pad + bytesRead;
- }
- else
- {
- // The last pad amount is left in the buffer.
- // Boundary can't be in there so write out the
- // data you have and signal an error condition.
- output.write(buffer, 0, pad);
- output.flush();
- total += pad;
- throw new MalformedStreamException(
- "Stream ended unexpectedly");
- }
- }
- /************************************
- * 读取进度
- ************************************/
- session.setAttribute("readsBytes", TypeChange.longToString(total));
- /***************************************/
- }
- output.flush();
- readsBytes = total;
- return total;
- }
- /**
- *
- * @return
- * @throws MalformedStreamException
- * @throws IOException
- */
- public int discardBodyData() throws MalformedStreamException,IOException{
- boolean done = false;
- int pad;
- int pos;
- int bytesRead;
- int total = 0;
- while (!done){
- // Is boundary token present somewere in the buffer?
- pos = findSeparator();
- if (pos != -1){
- // Write the rest of the data before the boundary.
- total += pos - head;
- head = pos;
- done = true;
- }else{
- // Determine how much data should be kept in the
- // buffer.
- if (tail - head > keepRegion)
- {
- pad = keepRegion;
- }
- else
- {
- pad = tail - head;
- }
- total += tail - head - pad;
- // Move the data to the beging of the buffer.
- System.arraycopy(buffer, tail - pad, buffer, 0, pad);
- // Refill buffer with new data.
- head = 0;
- bytesRead = input.read(buffer, pad, bufSize - pad);
- if (bytesRead != -1)
- {
- tail = pad + bytesRead;
- }
- else
- {
- // The last pad amount is left in the buffer.
- // Boundary can't be in there so signal an error
- // condition.
- total += pad;
- throw new MalformedStreamException(
- "Stream ended unexpectedly");
- }
- }
- }
- readsBytes = total;
- return total;
- }
- /**
- *
- * @return
- * @throws IOException
- */
- public boolean skipPreamble() throws IOException{
- // First delimiter may be not preceeded with a CRLF.
- System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2);
- boundaryLength = boundary.length - 2;
- try{
- // Discard all data up to the delimiter. 分隔符
- discardBodyData();
- // Read boundary - if succeded, the stream contains an
- // encapsulation.
- return readBoundary();
- }catch (MalformedStreamException e){
- return false;
- }
- finally{
- // Restore delimiter.
- System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2);
- boundaryLength = boundary.length;
- boundary[0] = 0x0D;
- boundary[1] = 0x0A;
- }
- }
- public static boolean arrayequals(byte[] a, byte[] b, int count){
- for (int i = 0; i < count; i++)
- {
- if (a[i] != b[i])
- {
- return false;
- }
- }
- return true;
- }
- protected int findByte(byte value,int pos){
- for (int i = pos; i < tail; i++)
- {
- if (buffer[i] == value)
- {
- return i;
- }
- }
- return -1;
- }
- protected int findSeparator() {
- int first;
- int match = 0;
- int maxpos = tail - boundaryLength;
- for (first = head;
- (first <= maxpos) && (match != boundaryLength);
- first++)
- {
- first = findByte(boundary[0], first);
- if (first == -1 || (first > maxpos))
- {
- return -1;
- }
- for (match = 1; match < boundaryLength; match++)
- {
- if (buffer[first + match] != boundary[match])
- {
- break;
- }
- }
- }
- if (match == boundaryLength)
- {
- return first - 1;
- }
- return -1;
- }
- public String toString(){
- StringBuffer sbTemp = new StringBuffer();
- sbTemp.append("boundary='");
- sbTemp.append(String.valueOf(boundary));
- sbTemp.append("'nbufSize=");
- sbTemp.append(bufSize);
- return sbTemp.toString();
- }
- public class MalformedStreamException extends IOException {
- /**
- * Constructs a <code>MalformedStreamException</code> with no
- * detail message.
- */
- public MalformedStreamException()
- {
- super();
- }
- /**
- * Constructs an <code>MalformedStreamException</code> with
- * the specified detail message.
- *
- * @param message The detail message.
- */
- public MalformedStreamException(String message)
- {
- super(message);
- }
- }
- public class IllegalBoundaryException extends IOException {
- /**
- * Constructs an <code>IllegalBoundaryException</code> with no
- * detail message.
- */
- public IllegalBoundaryException()
- {
- super();
- }
- /**
- * Constructs an <code>IllegalBoundaryException</code> with
- * the specified detail message.
- *
- * @param message The detail message.
- */
- public IllegalBoundaryException(String message)
- {
- super(message);
- }
- }
- /**
- * 读取进度
- */
- public long getReadsBytes(){
- return this.readsBytes;
- }
- // ------------------------------------------------------ Debugging methods
- // These are the methods that were used to debug this stuff.
- /*
- // Dump data.
- protected void dump()
- {
- System.out.println("01234567890");
- byte[] temp = new byte[buffer.length];
- for(int i=0; i<buffer.length; i++)
- {
- if (buffer[i] == 0x0D || buffer[i] == 0x0A)
- {
- temp[i] = 0x21;
- }
- else
- {
- temp[i] = buffer[i];
- }
- }
- System.out.println(new String(temp));
- int i;
- for (i=0; i<head; i++)
- System.out.print(" ");
- System.out.println("h");
- for (i=0; i<tail; i++)
- System.out.print(" ");
- System.out.println("t");
- System.out.flush();
- }
- // Main routine, for testing purposes only.
- //
- // @param args A String[] with the command line arguments.
- // @exception Exception, a generic exception.
- public static void main( String[] args )
- throws Exception
- {
- File boundaryFile = new File("boundary.dat");
- int boundarySize = (int)boundaryFile.length();
- byte[] boundary = new byte[boundarySize];
- FileInputStream input = new FileInputStream(boundaryFile);
- input.read(boundary,0,boundarySize);
- input = new FileInputStream("multipart.dat");
- MultipartStream chunks = new MultipartStream(input, boundary);
- int i = 0;
- String header;
- OutputStream output;
- boolean nextChunk = chunks.skipPreamble();
- while (nextChunk)
- {
- header = chunks.readHeaders();
- System.out.println("!"+header+"!");
- System.out.println("wrote part"+i+".dat");
- output = new FileOutputStream("part"+(i++)+".dat");
- chunks.readBodyData(output);
- nextChunk = chunks.readBoundary();
- }
- }
- */
- }