java文件上传

大概的协议格式为:

头呢有酱婶的信息:[注:${bound}这个是边界占位符会在body用到]

Content-Type: multipart/form-data; boundary=${bound}    

multipart/form-data body呢大概是酱婶的:

--${bound}  
Content-Disposition: form-data; name="Filename"  
  
HTTP.pdf  
--${bound}  
Content-Disposition: form-data; name="file000"; filename="HTTP协议详解.pdf"  
Content-Type: application/octet-stream  
  
%PDF-1.5  
file content  
%%EOF  
--${bound}  
Content-Disposition: form-data; name="Upload"  
  
Submit Query  
--${bound}--  

no picture say ge j8? 上栗子

Content-Type:
multipart/form-data; boundary=----WebKitFormBoundaryqao1oDQOjWcGVMoa


更有说服力的源码上场了:

commons-fileupload源码是酱婶说的:

public List parseRequest(RequestContext ctx) throws FileUploadException {
        List items = new ArrayList();
        boolean successful = false;
        boolean var21 = false;

        FileItem fileItem;
        ArrayList var29;
        try {
            var21 = true;
            FileItemIterator iter = this.getItemIterator(ctx);
            FileItemFactory fac = this.getFileItemFactory();
            if(fac == null) {
                throw new NullPointerException("No FileItemFactory has been set.");
            }

            while(true) {
                if(!iter.hasNext()) {
                    successful = true;
                    var29 = items;
                    var21 = false;
                    break;
                }

                FileItemStream item = iter.next();
                String fileName = ((FileUploadBase.FileItemIteratorImpl.FileItemStreamImpl)item).name;
                fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);
                items.add(fileItem);

                try {
                    Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
                } catch (FileUploadBase.FileUploadIOException var24) {
                    throw (FileUploadException)var24.getCause();
                } catch (IOException var25) {
                    throw new FileUploadBase.IOFileUploadException("Processing of multipart/form-data request failed. " + var25.getMessage(), var25);
                }

                if(fileItem instanceof FileItemHeadersSupport) {
                    FileItemHeaders fih = item.getHeaders();
                    ((FileItemHeadersSupport)fileItem).setHeaders(fih);
                }
            }
        } catch (FileUploadBase.FileUploadIOException var26) {
            throw (FileUploadException)var26.getCause();
        } catch (IOException var27) {
            throw new FileUploadException(var27.getMessage(), var27);
        } finally {
            if(var21) {
                if(!successful) {
                    Iterator iterator = items.iterator();

                    while(iterator.hasNext()) {
                        FileItem fileItem = (FileItem)iterator.next();

                        try {
                            fileItem.delete();
                        } catch (Throwable var22) {
                            ;
                        }
                    }
                }

            }
        }

        if(!successful) {
            Iterator iterator = items.iterator();

            while(iterator.hasNext()) {
                fileItem = (FileItem)iterator.next();

                try {
                    fileItem.delete();
                } catch (Throwable var23) {
                    ;
                }
            }
        }

        return var29;
    }
根据parseRequest方法中的Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
得知FileItemIterator 生出的 FileItemStream 和 怎么生的是我们关注的地方:

FileItemIterator:
FileItemIteratorImpl(RequestContext ctx) throws FileUploadException, IOException {
            if(ctx == null) {
                throw new NullPointerException("ctx parameter");
            } else {
                String contentType = ctx.getContentType();
                if(null != contentType && contentType.toLowerCase().startsWith("multipart/")) {
                    InputStream input = ctx.getInputStream();
                    if(FileUploadBase.this.sizeMax >= 0L) {
                        int requestSize = ctx.getContentLength();
                        if(requestSize == -1) {
                            input = new LimitedInputStream((InputStream)input, FileUploadBase.this.sizeMax) {
                                protected void raiseError(long pSizeMax, long pCount) throws IOException {
                                    FileUploadException ex = new FileUploadBase.SizeLimitExceededException("the request was rejected because its size (" + pCount + ") exceeds the configured maximum" + " (" + pSizeMax + ")", pCount, pSizeMax);
                                    throw new FileUploadBase.FileUploadIOException(ex);
                                }
                            };
                        } else if(FileUploadBase.this.sizeMax >= 0L && (long)requestSize > FileUploadBase.this.sizeMax) {
                            throw new FileUploadBase.SizeLimitExceededException("the request was rejected because its size (" + requestSize + ") exceeds the configured maximum (" + FileUploadBase.this.sizeMax + ")", (long)requestSize, FileUploadBase.this.sizeMax);
                        }
                    }

                    String charEncoding = FileUploadBase.this.headerEncoding;
                    if(charEncoding == null) {
                        charEncoding = ctx.getCharacterEncoding();
                    }

                    this.boundary = FileUploadBase.this.getBoundary(contentType);
                    if(this.boundary == null) {
                        throw new FileUploadException("the request was rejected because no multipart boundary was found");
                    } else {
                        this.notifier = new ProgressNotifier(FileUploadBase.this.listener, (long)ctx.getContentLength());
                        this.multi = new MultipartStream((InputStream)input, this.boundary, this.notifier);
                        this.multi.setHeaderEncoding(charEncoding);
                        this.skipPreamble = true;
                        this.findNextItem();
                    }
                } else {
                    throw new FileUploadBase.InvalidContentTypeException("the request doesn't contain a multipart/form-data or multipart/mixed stream, content type header is " + contentType);
                }
            }
        }

呜呜喳喳一大堆,发现了这个:MultipartStream构造如下:
this.input = input;
        this.bufSize = bufSize;
        this.buffer = new byte[bufSize];
        this.notifier = pNotifier;
        this.boundary = new byte[boundary.length + BOUNDARY_PREFIX.length];
        this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length;
        this.keepRegion = this.boundary.length;
        System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, BOUNDARY_PREFIX.length);
        System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, boundary.length);
        this.head = 0;
        this.tail = 0;
很显然boundary被保留起来了;
 

在FileItemStream中发现:

FileItemStreamImpl(String pName, String pFieldName, String pContentType, boolean pFormField, long pContentLength) throws IOException {
                this.name = pName;
                this.fieldName = pFieldName;
                this.contentType = pContentType;
                this.formField = pFormField;
                final ItemInputStream itemStream = FileItemIteratorImpl.this.multi.newInputStream();
                InputStream istream = itemStream;
                if(FileUploadBase.this.fileSizeMax != -1L) {
                    if(pContentLength != -1L && pContentLength > FileUploadBase.this.fileSizeMax) {
                        FileUploadBase.FileSizeLimitExceededException e = new FileUploadBase.FileSizeLimitExceededException("The field " + this.fieldName + " exceeds its maximum permitted " + " size of " + FileUploadBase.this.fileSizeMax + " bytes.", pContentLength, FileUploadBase.this.fileSizeMax);
                        e.setFileName(pName);
                        e.setFieldName(pFieldName);
                        throw new FileUploadBase.FileUploadIOException(e);
                    }

                    istream = new LimitedInputStream(itemStream, FileUploadBase.this.fileSizeMax) {
                        protected void raiseError(long pSizeMax, long pCount) throws IOException {
                            itemStream.close(true);
                            FileUploadBase.FileSizeLimitExceededException e = new FileUploadBase.FileSizeLimitExceededException("The field " + FileItemStreamImpl.this.fieldName + " exceeds its maximum permitted " + " size of " + pSizeMax + " bytes.", pCount, pSizeMax);
                            e.setFieldName(FileItemStreamImpl.this.fieldName);
                            e.setFileName(FileItemStreamImpl.this.name);
                            throw new FileUploadBase.FileUploadIOException(e);
                        }
                    };
                }

                this.stream = (InputStream)istream;
            }
MultipartStream.ItemInputStream newInputStream() {
    return new MultipartStream.ItemInputStream();
}

multi也就是MultipartStream被用来开流了,MultipartStream又用到了ItemInputStream

以下部分开始处理那body里的数据了,反正看起来很厉害的样子。

ItemInputStream() {
            this.findSeparator();
        }

        private void findSeparator() {
            this.pos = MultipartStream.this.findSeparator();
            if(this.pos == -1) {
                if(MultipartStream.this.tail - MultipartStream.this.head > MultipartStream.this.keepRegion) {
                    this.pad = MultipartStream.this.keepRegion;
                } else {
                    this.pad = MultipartStream.this.tail - MultipartStream.this.head;
                }
            }

        }
public int available() throws IOException {
            return this.pos == -1?MultipartStream.this.tail - MultipartStream.this.head - this.pad:this.pos - MultipartStream.this.head;
        }

        public int read() throws IOException {
            if(this.closed) {
                throw new ItemSkippedException();
            } else if(this.available() == 0 && this.makeAvailable() == 0) {
                return -1;
            } else {
                ++this.total;
                int b = MultipartStream.this.buffer[MultipartStream.this.head++];
                return b >= 0?b:b + 256;
            }
        }

        public int read(byte[] b, int off, int len) throws IOException {
            if(this.closed) {
                throw new ItemSkippedException();
            } else if(len == 0) {
                return 0;
            } else {
                int res = this.available();
                if(res == 0) {
                    res = this.makeAvailable();
                    if(res == 0) {
                        return -1;
                    }
                }

                res = Math.min(res, len);
                System.arraycopy(MultipartStream.this.buffer, MultipartStream.this.head, b, off, res);
                MultipartStream.this.head = res;
                this.total += (long)res;
                return res;
            }
        }

private int makeAvailable() throws IOException {
            if(this.pos != -1) {
                return 0;
            } else {
                this.total += (long)(MultipartStream.this.tail - MultipartStream.this.head - this.pad);
                System.arraycopy(MultipartStream.this.buffer, MultipartStream.this.tail - this.pad, MultipartStream.this.buffer, 0, this.pad);
                MultipartStream.this.head = 0;
                MultipartStream.this.tail = this.pad;

                int av;
                do {
                    int bytesRead = MultipartStream.this.input.read(MultipartStream.this.buffer, MultipartStream.this.tail, MultipartStream.this.bufSize - MultipartStream.this.tail);
                    if(bytesRead == -1) {
                        String msg = "Stream ended unexpectedly";
                        throw new MultipartStream.MalformedStreamException("Stream ended unexpectedly");
                    }

                    if(MultipartStream.this.notifier != null) {
                        MultipartStream.this.notifier.noteBytesRead(bytesRead);
                    }

                    MultipartStream.this.tail = bytesRead;
                    this.findSeparator();
                    av = this.available();
                } while(av <= 0 && this.pos == -1);

                return av;
            }
        }


基本完成只能说666...

spring:

servlet:



未完待续...

参考:(请以协议为准,其他资料仅供参考)

http1.1协议 点击打开链接 点击打开链接 点击打开链接 点击打开链接

百度http协议点击打开链接

spring-multipart API 点击打开链接

servlet3.0 点击打开链接

fileupload 点击打开链接 点击打开链接 点击打开链接

单文件servlet API 点击打开链接 点击打开链接 点击打开链接

http multipart 点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值