看看这个对象的getParameter的方法
// Copyright (C) 1998 by Jason Hunter <[email protected]>.  All rights reserved.
// Use of this class is limited.  Please see the LICENSE for more information.package com.oreilly.servlet;import java.io.*;
import java.util.*;
import javax.servlet.*;
import java.lang.*;
import javax.servlet.http.*;/**
 * A utility class to handle <tt>multipart/form-data</tt> requests,
 * the kind of requests that support file uploads.  This class can
 * receive arbitrarily large files (up to an artificial limit you can set),
 * and fairly efficiently too.
 * It cannot handle nested data (multipart content within multipart content)
 * or internationalized content (such as non Latin-1 filenames).
 * <p>
 * It's used like this:
 * <blockquote><pre>
 * MultipartRequest multi = new MultipartRequest(req, ".");
 * &nbsp;
 * out.println("Params:");
 * Enumeration params = multi.getParameterNames();
 * while (params.hasMoreElements()) {
 *   String name = (String)params.nextElement();
 *   String value = multi.getParameter(name);
 *   out.println(name + " = " + value);
 * }
 * out.println();
 * &nbsp;
 * out.println("Files:");
 * Enumeration files = multi.getFileNames();
 * while (files.hasMoreElements()) {
 *   String name = (String)files.nextElement();
 *   String filename = multi.getFilesystemName(name);
 *   String type = multi.getContentType(name);
 *   File f = multi.getFile(name);
 *   out.println("name: " + name);
 *   out.println("filename: " + filename);
 *   out.println("type: " + type);
 *   if (f != null) {
 *     out.println("f.toString(): " + f.toString());
 *     out.println("f.getName(): " + f.getName());
 *     out.println("f.exists(): " + f.exists());
 *     out.println("f.length(): " + f.length());
 *     out.println();
 *   }
 * }
 * </pre></blockquote>
 *
 * A client can upload files using an HTML form with the following structure.
 * Note that not all browsers support file uploads.
 * <blockquote><pre>
 * &lt;FORM ACTION="/servlet/Handler" METHOD=POST
 *          ENCTYPE="multipart/form-data"&gt;
 * What is your name? &lt;INPUT TYPE=TEXT NAME=submitter&gt; &lt;BR&gt;
 * Which file to upload? &lt;INPUT TYPE=FILE NAME=file&gt; &lt;BR&gt;
 * &lt;INPUT TYPE=SUBMIT&GT;
 * &lt;/FORM&gt;
 * </pre></blockquote>
 * <p>
 * The full file upload specification is contained in experimental RFC 1867,
 * available at <a href="http://www.ietf.org/rfc/rfc1867.txt">
 * http://www.ietf.org/rfc/rfc1867.txt</a>.
 *
 * @author <b>Jason Hunter</b>, Copyright &#169; 1998-1999
 * @version 1.6, 00/03/19, better WebSphere 2.x/3.x content type workaround
 * @version 1.5, 00/02/04, added auto MacBinary decoding for IE on Mac
 * @version 1.4, 00/01/05, added getParameterValues(),
 *                         WebSphere 2.x getContentType() workaround,
 *                         stopped writing empty "unknown" file
 * @version 1.3, 99/12/28, IE4 on Win98 lastIndexOf("boundary=") workaround
 * @version 1.2, 99/12/20, IE4 on Mac readNextPart() workaround
 * @version 1.1, 99/01/15, JSDK readLine() bug workaround
 * @version 1.0, 98/09/18
 */
public class MultipartRequest {  private static final int DEFAULT_MAX_POST_SIZE = 1024 * 1024 * 10;  // 1 Meg
  private static final String NO_FILE = "unknown";  private HttpServletRequest req;
  private File dir=null;
  private int maxSize;
  private String tempFilename;  //add by lzl
  private boolean defaultFileFlag=false; //add by lzl
  private int fileNo=1; //add by lzl
  private Hashtable fileFullPaths; // add by wguzgg
  private Hashtable fileLengths;  //add by wguzgg
  private Hashtable fileLocalPaths; // add by wguzgg
  private Hashtable parameters = new Hashtable();  // name - Vector of values
  private Hashtable files = new Hashtable();       // name - UploadedFile
  //add by wguzgg
  public long getFileLengths(String fn) {
    Long fl=(Long)fileLengths.get(fn);
    return fl.longValue();
  }  //add by wguzgg
  public String getFileFullPath(String fn) {
    String fp=(String)fileFullPaths.get(fn);
    return fp;
  }  //add by wguzgg
  public String getFileLocalPath(String fn) {
    String flp=(String)fileLocalPaths.get(fn);
    return flp;
  }  //add by lzl
  public MultipartRequest(HttpServletRequest request,String saveDirectory,boolean fileFlag) throws IOException {
    this(request, saveDirectory, DEFAULT_MAX_POST_SIZE,fileFlag);
  } /**
   * Constructs a new MultipartRequest to handle the specified request,
   * saving any uploaded files to the given directory, and limiting the
   * upload size to 1 Megabyte.  If the content is too large, an
   * IOException is thrown.  This constructor actually parses the
   * <tt>multipart/form-data</tt> and throws an IOException if there's any
   * problem reading or parsing the request.
   *
   * @param request the servlet request
   * @param saveDirectory the directory in which to save any uploaded files
   * @exception IOException if the uploaded content is larger than 1 Megabyte
   * or there's a problem reading or parsing the request
   */
  public MultipartRequest(HttpServletRequest request,
                          String saveDirectory) throws IOException {
    this(request, saveDirectory, DEFAULT_MAX_POST_SIZE);
  }  /**
   * Constructs a new MultipartRequest to handle the specified request,
   * saving any uploaded files to the given directory, and limiting the
   * upload size to the specified length.  If the content is too large, an
   * IOException is thrown.  This constructor actually parses the
   * <tt>multipart/form-data</tt> and throws an IOException if there's any
   * problem reading or parsing the request.
   *
   * @param request the servlet request
   * @param saveDirectory the directory in which to save any uploaded files
   * @param maxPostSize the maximum size of the POST content
   * @exception IOException if the uploaded content is larger than
   * <tt>maxPostSize</tt> or there's a problem reading or parsing the request
   */
  public MultipartRequest(HttpServletRequest request,
                          String saveDirectory,
                          int maxPostSize) throws IOException {
    // Sanity check values
    if (request == null)
      throw new IllegalArgumentException("request cannot be null");
    if (saveDirectory == null)
      throw new IllegalArgumentException("saveDirectory cannot be null");
    if (maxPostSize <= 0) {
      throw new IllegalArgumentException("maxPostSize must be positive");
    }    // Save the request, dir, and max size
    req = request;
      dir = new File(saveDirectory);
    maxSize = maxPostSize;
      tempFilename=saveDirectory.substring(saveDirectory.lastIndexOf("/"));
    // Check saveDirectory is truly a directory
      if (!dir.isDirectory())
        throw new IllegalArgumentException("Not a directory: " + saveDirectory);    // Check saveDirectory is writable
      if (!dir.canWrite())
        throw new IllegalArgumentException("Not writable: " + saveDirectory);    // Now parse the request saving data to "parameters" and "files";
    // write the file contents to the saveDirectory
    readRequest();
  }  //add by lzl
    public MultipartRequest(HttpServletRequest request,
                          String saveDirectory,
                          int maxPostSize,boolean fileFlag) throws IOException {
    // Sanity check values
    if (request == null)
      throw new IllegalArgumentException("request cannot be null");
    if (saveDirectory == null)
      throw new IllegalArgumentException("saveDirectory cannot be null");
    if (maxPostSize <= 0) {
      throw new IllegalArgumentException("maxPostSize must be positive");
    }    // Save the request, dir, and max size
    req = request;
      dir = new File(saveDirectory);
    maxSize = maxPostSize;
      tempFilename=saveDirectory.substring(saveDirectory.lastIndexOf("/"));
    defaultFileFlag=fileFlag;
    // Check saveDirectory is truly a directory
      if (!dir.isDirectory())
        throw new IllegalArgumentException("Not a directory: " + saveDirectory);    // Check saveDirectory is writable
      if (!dir.canWrite())
        throw new IllegalArgumentException("Not writable: " + saveDirectory);    // Now parse the request saving data to "parameters" and "files";
    // write the file contents to the saveDirectory
    readRequest();
  }
  /**
   * Constructor with an old signature, kept for backward compatibility.
   * Without this constructor, a servlet compiled against a previous version
   * of this class (pre 1.4) would have to be recompiled to link with this
   * version.  This constructor supports the linking via the old signature.
   * Callers must simply be careful to pass in an HttpServletRequest.
   *
   */
  public MultipartRequest(ServletRequest request,
                          String saveDirectory) throws IOException {
    this((HttpServletRequest)request, saveDirectory);
  }  /**
   * Constructor with an old signature, kept for backward compatibility.
   * Without this constructor, a servlet compiled against a previous version
   * of this class (pre 1.4) would have to be recompiled to link with this
   * version.  This constructor supports the linking via the old signature.
   * Callers must simply be careful to pass in an HttpServletRequest.
   *
   */
  public MultipartRequest(ServletRequest request,
                          String saveDirectory,
                          int maxPostSize) throws IOException {
    this((HttpServletRequest)request, saveDirectory, maxPostSize);
  }  /**
   * Returns the names of all the parameters as an Enumeration of
   * Strings.  It returns an empty Enumeration if there are no parameters.
   *
   * @return the names of all the parameters as an Enumeration of Strings
   */
  public Enumeration getParameterNames() {
    return parameters.keys();
  }  /**
   * Returns the names of all the uploaded files as an Enumeration of
   * Strings.  It returns an empty Enumeration if there are no uploaded
   * files.  Each file name is the name specified by the form, not by
   * the user.
   *
   * @return the names of all the uploaded files as an Enumeration of Strings
   */
  public Enumeration getFileNames() {
    return files.keys();
  }  /**
   * Returns the value of the named parameter as a String, or null if
   * the parameter was not sent or was sent without a value.  The value
   * is guaranteed to be in its normal, decoded form.  If the parameter
   * has multiple values, only the last one is returned (for backward
   * compatibility).  For parameters with multiple values, it's possible
   * the last "value" may be null.
   *
   * @param name the parameter name
   * @return the parameter value
   */
  public String getParameter(String name) {
    try {
      Vector values = (Vector)parameters.get(name);
      if (values == null || values.size() == 0) {
        return null;
      }
      String value = (String)values.elementAt(values.size() - 1);
      return value;
    }
    catch (Exception e) {
      return null;
    }
  }  /**
   * Returns the values of the named parameter as a String array, or null if
   * the parameter was not sent.  The array has one entry for each parameter
   * field sent.  If any field was sent without a value that entry is stored
   * in the array as a null.  The values are guaranteed to be in their
   * normal, decoded form.  A single value is returned as a one-element array.
   *
   * @param name the parameter name
   * @return the parameter values
   */
  public String[] getParameterValues(String name) {
    try {
      Vector values = (Vector)parameters.get(name);
      if (values == null || values.size() == 0) {
        return null;
      }
      String[] valuesArray = new String[values.size()];
      values.copyInto(valuesArray);
      return valuesArray;
    }
    catch (Exception e) {
      return null;
    }
  }  /**
   * Returns the filesystem name of the specified file, or null if the
   * file was not included in the upload.  A filesystem name is the name
   * specified by the user.  It is also the name under which the file is
   * actually saved.
   *
   * @param name the file name
   * @return the filesystem name of the file
   */
  public String getFilesystemName(String name) {
    try {
      UploadedFile file = (UploadedFile)files.get(name);
      return file.getFilesystemName();  // may be null
    }
    catch (Exception e) {
      return null;
    }
  }  /**
   * Returns the content type of the specified file (as supplied by the
   * client browser), or null if the file was not included in the upload.
   *
   * @param name the file name
   * @return the content type of the file
   */
  public String getContentType(String name) {
    try {
      UploadedFile file = (UploadedFile)files.get(name);
      return file.getContentType();  // may be null
    }
    catch (Exception e) {
      return null;
    }
  }  /**
   * Returns a File object for the specified file saved on the server's
   * filesystem, or null if the file was not included in the upload.
   *
   * @param name the file name
   * @return a File object for the named file
   */
  public File getFile(String name) {
    try {
      UploadedFile file = (UploadedFile)files.get(name);
      return file.getFile();  // may be null
    }
    catch (Exception e) {
      return null;
    }
  }  /**
   * The workhorse method that actually parses the request.  A subclass
   * can override this method for a better optimized or differently
   * behaved implementation.
   *
   * @exception IOException if the uploaded content is larger than
   * <tt>maxSize</tt> or there's a problem parsing the request
   */
  protected void readRequest() throws IOException {
    // Check the content length to prevent denial of service attacks
    int length = req.getContentLength();
    if (length > maxSize) {
      throw new IOException("Posted content length of " + length +
                            " exceeds limit of " + maxSize);
    }    // Check the content type to make sure it's "multipart/form-data"
    // Access header two ways to work around WebSphere oddities
    String type = null;
    String type1 = req.getHeader("Content-Type");
    String type2 = req.getContentType();
    // If one value is null, choose the other value
    if (type1 == null && type2 != null) {
      type = type2;
    }
    else if (type2 == null && type1 != null) {
      type = type1;
    }
    // If neither value is null, choose the longer value
    else if (type1 != null && type2 != null) {
      type = (type1.length() > type2.length() ? type1 : type2);
    }    if (type == null ||
        !type.toLowerCase().startsWith("multipart/form-data")) {
      throw new IOException("Posted content type isn't multipart/form-data");
    }
    // Get the boundary string; it's included in the content type.
    // Should look something like "------------------------12012133613061"
    String boundary = extractBoundary(type);
    if (boundary == null) {
      throw new IOException("Separation boundary was not specified");
    }    // Construct the special input stream we'll read from
    MultipartInputStreamHandler in =
      new MultipartInputStreamHandler(req.getInputStream(), length);    // Read the first line, should be the first boundary
    String line = in.readLine();
    if (line == null) {
      throw new IOException("Corrupt form data: premature ending");
    }    // Verify that the line is the boundary
    if (!line.startsWith(boundary)) {
      throw new IOException("Corrupt form data: no leading boundary");
    }    // Now that we're just beyond the first boundary, loop over each part
    boolean done = false;
    while (!done) {
      done = readNextPart(in, boundary);
    }
  }  /**
   * A utility method that reads an individual part.  Dispatches to
   * readParameter() and readAndSaveFile() to do the actual work.  A
   * subclass can override this method for a better optimized or
   * differently behaved implementation.
   *
   * @param in the stream from which to read the part
   * @param boundary the boundary separating parts
   * @return a flag indicating whether this is the last part
   * @exception IOException if there's a problem reading or parsing the
   * request
   *
   * @see readParameter
   * @see readAndSaveFile
   */
  protected boolean readNextPart(MultipartInputStreamHandler in,
                                 String boundary) throws IOException {
    // Read the first line, should look like this:
    // content-disposition: form-data; name="field1"; filename="file1.txt"
    String line = in.readLine();
    if (line == null) {
      // No parts left, we're done
      return true;
    }
    else if (line.length() == 0) {
      // IE4 on Mac sends an empty line at the end; treat that as the end.
      // Thanks to Daniel Lemire and Henri Tourigny for this fix.
      return true;
    }    // Parse the content-disposition line
    String[] dispInfo = extractDispositionInfo(line);
    String disposition = dispInfo[0];
    String name = dispInfo[1];
    String filename =  dispInfo[2];    // Now onto the next line.  This will either be empty
    // or contain a Content-Type and then an empty line.
    line = in.readLine();
    if (line == null) {
      // No parts left, we're done
      return true;
    }    // Get the content type, or null if none specified
    String contentType = extractContentType(line);
    if (contentType != null) {
      // Eat the empty line
      line = in.readLine();
      if (line == null || line.length() > 0) {  // line should be empty
        throw new
          IOException("Malformed line after content type: " + line);
      }
    }
    else {
      // Assume a default content type
      contentType = "application/octet-stream";
    }    // Now, finally, we read the content (end after reading the boundary)
    if (filename == null) {
      // This is a parameter, add it to the vector of values
      String value = readParameter(in, boundary);
      if (value.equals("")) {
        value = null;  // treat empty strings like nulls
      }
      Vector existingValues = (Vector)parameters.get(name);
      if (existingValues == null) {
        existingValues = new Vector();
        parameters.put(name, existingValues);
      }
      existingValues.addElement(value);
    }
    else {
      // This is a file
      readAndSaveFile(in, boundary, filename, contentType,name);
      if (fileLocalPaths==null)                                       //add by wguzgg
        fileLocalPaths=new Hashtable();                               //add by wguzgg
      fileLocalPaths.put(new String(filename),dir.getAbsolutePath()); //add by wguzgg
      if (fileLengths==null)                                  //add by wguzgg
        fileLengths=new Hashtable();                          //add by wguzgg
      File f = new File(dir + File.separator + filename);     //add by wguzgg
      Long fileLength=new Long(f.length());                   //add by wguzgg
      fileLengths.put(new String(filename),fileLength);                   //add by wguzgg
      if (filename.equals(NO_FILE)) {
        files.put(name, new UploadedFile(null, null, null));
      }
      else {
        if(fileNo==1 && !defaultFileFlag){
          String fileType=filename.substring(filename.indexOf("."));
          filename=""+tempFilename+fileType.trim();
        }
        files.put(name,new UploadedFile(dir.toString(), filename, contentType));
        fileNo++;
      }
    }
    return false;  // there's more to read
  }  /**
   * A utility method that reads a single part of the multipart request
   * that represents a parameter.  A subclass can override this method
   * for a better optimized or differently behaved implementation.
   *
   * @param in the stream from which to read the parameter information
   * @param boundary the boundary signifying the end of this part
   * @return the parameter value
   * @exception IOException if there's a problem reading or parsing the
   * request
   */
  protected String readParameter(MultipartInputStreamHandler in,
                                 String boundary) throws IOException {
    StringBuffer sbuf = new StringBuffer();
    String line;    while ((line = in.readLine()) != null) {
      if (line.startsWith(boundary)) break;
      sbuf.append(line + "\r\n");  // add the \r\n in case there are many lines
    }    if (sbuf.length() == 0) {
      return null;  // nothing read
    }    sbuf.setLength(sbuf.length() - 2);  // cut off the last line's \r\n
    return sbuf.toString();  // no URL decoding needed
  }  /**
   * A utility method that reads a single part of the multipart request
   * that represents a file, and saves the file to the given directory.
   * A subclass can override this method for a better optimized or
   * differently behaved implementation.
   *
   * @param in the stream from which to read the file
   * @param boundary the boundary signifying the end of this part
   * @param dir the directory in which to save the uploaded file
   * @param filename the name under which to save the uploaded file
   * @exception IOException if there's a problem reading or parsing the
   * request
   */
  protected void readAndSaveFile(MultipartInputStreamHandler in,
                                 String boundary,
                                 String filename,
                                 String contentType,
                                 String name) throws IOException {
    OutputStream out = null;
    // A filename of NO_FILE means no file was sent, so just read to the
    // next boundary and ignore the empty contents
    if (filename.equals(NO_FILE)) {
      out = new ByteArrayOutputStream();  // write to nowhere
    }
    // A MacBinary file goes through a decoder
    else if (contentType.equals("application/x-macbinary")){
      File f = new File(dir + File.separator + filename);
      out = new MacBinaryDecoderOutputStream(
            new BufferedOutputStream(
            new FileOutputStream(f), 8 * 1024));
    }
    // A real file's contents are written to disk
    else {
      if(fileNo==1 && !defaultFileFlag){
        String fileType=filename.substring(filename.indexOf("."));
        filename=""+tempFilename+fileType.trim();
      }
      File f = new File(dir + File.separator + filename);
      out = new BufferedOutputStream(new FileOutputStream(f), 8 * 1024);
    }    byte[] bbuf = new byte[100 * 1024];  // 100K
    int result;
    String line;    // ServletInputStream.readLine() has the annoying habit of
    // adding a \r\n to the end of the last line.
    // Since we want a byte-for-byte transfer, we have to cut those chars.
    boolean rnflag = false;
    while ((result = in.readLine(bbuf, 0, bbuf.length)) != -1) {
      // Check for boundary
      if (result > 2 && bbuf[0] == '-' && bbuf[1] == '-') { // quick pre-check
        line = new String(bbuf, 0, result); //has edited by lzl
        if (line.startsWith(boundary)) break;
      }
      // Are we supposed to write \r\n for the last iteration?
      if (rnflag) {
        out.write('\r'); out.write('\n');
        rnflag = false;
      }
      // Write the buffer, postpone any ending \r\n
      if (result >= 2 &&
          bbuf[result - 2] == '\r' &&
          bbuf[result - 1] == '\n') {
        out.write(bbuf, 0, result - 2);  // skip the last 2 chars
        rnflag = true;  // make a note to write them on the next iteration
      }
      else {
        out.write(bbuf, 0, result);
      }
    }
    out.flush();
    out.close();
  }  // Extracts and returns the boundary token from a line.
  //
  private String extractBoundary(String line) {
    // Use lastIndexOf() because IE 4.01 on Win98 has been known to send the
    // "boundary=" string multiple times.  Thanks to David Wall for this fix.
    int index = line.lastIndexOf("boundary=");
    if (index == -1) {
      return null;
    }
    String boundary = line.substring(index + 9);  // 9 for "boundary="    // The real boundary is always preceeded by an extra "--"
    boundary = "--" + boundary;    return boundary;
  }  // Extracts and returns disposition info from a line, as a String array
  // with elements: disposition, name, filename.  Throws an IOException
  // if the line is malformatted.
  //
  private String[] extractDispositionInfo(String line) throws IOException {
    // Return the line's data as an array: disposition, name, filename
    String[] retval = new String[3];    // Convert the line to a lowercase string without the ending \r\n
    // Keep the original line for error messages and for variable names.
    String origline = line;
    line = origline.toLowerCase();    // Get the content disposition, should be "form-data"
    int start = line.indexOf("content-disposition: ");
    int end = line.indexOf(";");
    if (start == -1 || end == -1) {
      throw new IOException("Content disposition corrupt: " + origline);
    }
    String disposition = line.substring(start + 21, end);
    if (!disposition.equals("form-data")) {
      throw new IOException("Invalid content disposition: " + disposition);
    }    // Get the field name
    start = line.indexOf("name=\"", end);  // start at last semicolon
    end = line.indexOf("\"", start + 7);   // skip name=\"
    if (start == -1 || end == -1) {
      throw new IOException("Content disposition corrupt: " + origline);
    }
    String name = origline.substring(start + 6, end);    // Get the filename, if given
    String filename = null;
    start = line.indexOf("filename=\"", end + 2);  // start after name
    end = line.indexOf("\"", start + 10);          // skip filename=\"
    if (start != -1 && end != -1) {                // note the !=
      filename = origline.substring(start + 10, end);
      String temp=new String(filename);               //add by wguzgg
      // The filename may contain a full path.  Cut to just the filename.
      int slash =
        Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
      if (slash > -1) {
        filename = filename.substring(slash + 1);  // past last slash
      }
      if (filename.equals("")) filename = NO_FILE; // sanity check
      if (fileFullPaths==null)                       //add by wguzgg
        fileFullPaths=new Hashtable();               //add by wguzgg
      fileFullPaths.put(new String(filename),temp);              //add by wguzgg
    }    // Return a String array: disposition, name, filename
    retval[0] = disposition;
    retval[1] = name;
    retval[2] = filename;
    return retval;
  }  // Extracts and returns the content type from a line, or null if the
  // line was empty.  Throws an IOException if the line is malformatted.
  //
  private String extractContentType(String line) throws IOException {
    String contentType = null;    // Convert the line to a lowercase string
    String origline = line;
    line = origline.toLowerCase();    // Get the content type, if any
    if (line.startsWith("content-type")) {
      int start = line.indexOf(" ");
      if (start == -1) {
        throw new IOException("Content type corrupt: " + origline);
      }
      contentType = line.substring(start + 1);
    }
    else if (line.length() != 0) {  // no content type, so should be empty
      throw new IOException("Malformed line after disposition: " + origline);
    }    return contentType;
  }
}
// A class to hold information about an uploaded file.
//
class UploadedFile {  private String dir;
  private String filename;
  private String type;  UploadedFile(String dir, String filename, String type) {
    this.dir = dir;
    this.filename = filename;
    this.type = type;
  }  public String getContentType() {
    return type;
  }  public String getFilesystemName() {
    return filename;
  }  public File getFile() {
    if (dir == null || filename == null) {
      return null;
    }
    else {
      return new File(dir + File.separator + filename);
    }
  }
}
// A class to aid in reading multipart/form-data from a ServletInputStream.
// It keeps track of how many bytes have been read and detects when the
// Content-Length limit has been reached.  This is necessary since some
// servlet engines are slow to notice the end of stream.
//
// Mac users: The Mac doesn't like class names which exceed 32 characters
// (including the ".class") so while this class is usable from a JAR
// anywhere, it won't compile on a Mac.
//
class MultipartInputStreamHandler {  ServletInputStream in;
  int totalExpected;
  int totalRead = 0;
  byte[] buf = new byte[8 * 1024];  public MultipartInputStreamHandler(ServletInputStream in,
                                     int totalExpected) {
    this.in = in;
    this.totalExpected = totalExpected;
  }  // Reads the next line of input.  Returns null to indicate the end
  // of stream.
  //
  public String readLine() throws IOException {
    StringBuffer sbuf = new StringBuffer();
    int result;
    String line;    do {
      result = this.readLine(buf, 0, buf.length);  // this.readLine() does +=
      if (result != -1) {
        sbuf.append(new String(buf, 0, result)); //has edited by lzl
      }
    } while (result == buf.length);  // loop only if the buffer was filled    if (sbuf.length() == 0) {
      return null;  // nothing read, must be at the end of stream
    }    sbuf.setLength(sbuf.length() - 2);  // cut off the trailing \r\n
    return sbuf.toString();
  }  // A pass-through to ServletInputStream.readLine() that keeps track
  // of how many bytes have been read and stops reading when the
  // Content-Length limit has been reached.
  //
  public int readLine(byte b[], int off, int len) throws IOException {
    if (totalRead >= totalExpected) {
      return -1;
    }
    else {
      if (len > (totalExpected - totalRead)) {
        len = totalExpected - totalRead;  // keep from reading off end
      }
      int result = in.readLine(b, off, len);
      if (result > 0) {
        totalRead += result;
      }
      return result;
    }
  }
}
// Class to filters MacBinary files to normal files on the fly
// Optimized for speed more than readability
class MacBinaryDecoderOutputStream extends FilterOutputStream {  int bytesFiltered = 0;
  int dataForkLength = 0;  public MacBinaryDecoderOutputStream(OutputStream out) {
    super(out);
  }  public void write(int b) throws IOException {
    // Bytes 83 through 86 are a long representing the data fork length
    // Check <= 86 first to short circuit early in the common case
    if (bytesFiltered <= 86 && bytesFiltered >= 83) {
      int leftShift = (86 - bytesFiltered) * 8;
      dataForkLength = dataForkLength | (b & 0xff) << leftShift;
    }
    // Bytes 128 up to (128 + dataForkLength - 1) are the data fork
    else if (bytesFiltered < (128 + dataForkLength) && bytesFiltered >= 128) {
      out.write(b);
    }
    bytesFiltered++;
  }  public void write(byte b[]) throws IOException {
    write(b, 0, b.length);
  }  public void write(byte b[], int off, int len) throws IOException {
    // If the write is for content past the end of the data fork, ignore
    if (bytesFiltered >= (128 + dataForkLength)) {
      bytesFiltered += len;
    }
    // If the write is entirely within the data fork, write it directly
    else if (bytesFiltered >= 128 &&
             (bytesFiltered + len) <= (128 + dataForkLength)) {
      out.write(b, off, len);
      bytesFiltered += len;
    }
    // Otherwise, do the write a byte at a time to get the logic above
    else {
      for (int i = 0 ; i < len ; i++) {
        write(b[off + i]);
      }
    }
  }
}

解决方案 »

  1.   

    非常感谢!!
    请问您的代码是自己写的还是开放的源码?我从那里可以获得更多的资料呢?
    还有我想从页面获得一些个人信息,比如是谁在上载,这样的数据应该如何传递?
    好像页面如果指定了ENCTYPE="multipart/form-data"的话,直接写的表单就不能传递了
      
      

  2.   

    /**
     * Description:  A Thread safe class for parsing a Servlet's InputStream.  It is especially usefull when the HTML form that
     *               the servlet is processing is of multipart/form-data
     * Copyright:    Copyright (c) Dane S. Foster<p>
     * @author Dane S. Foster <mailto:[email protected]>
     * @version 1.1
     */
    import java.io.*;
    import java.util.*;
    import javax.servlet.*;
    public class MultipartFormReader
    {
        private final int READY = 0;
        private final int FILENAME = 1;
        private final int NAME = 2;
        private final int BINDATA = 3;
        private final int TXTDATA = 4;    /**
         * Parses the ServletInputStream of encoding multipart/form-data and separates it into name value pairs.  The name-value pairs
         * are stored in the <code>map</code> argument.  There are a couple of this to be aware of.  This class is not a replacement for
         * the ServletRequest class but augments it.  It should only be used in the case where the client is issuing an HTTP POST request
         * and the form-encoding is multipart/form-data.
         *
         * <p>In the event the HTTP POST request contains binary data --for example, when someone
         * wants to upload data to your servlet-- it is stored as a byte array.  You can retrieve the binary data by calling the get method
         * on the <code>map</code> object you passed in as a parameter.
         * <p>i.e.: byte[] uploadedImage = (byte[]) map.get( "fieldname" );<p>
         * There is no limit to the amount of binary data that can be uploaded and retrieved.
         *
         * <p>For those situations where the HTTP POST request contains list data (i.e. checkboxes, multiple selection lists), the list data
         * is stored in a <code>java.util.List</code> object.  This is equivalent to the <code>javax.servlet.ServletRequest</code>'s
         * <code>public String[] getParameterValues( java.lang.String )</code> method.
         *<p>i.e.: java.util.List checkboxItems = (java.util.List)map.get( "fieldname" );
         *
         * @param   request     A <code>ServletRequest</code> object.
         * @param   map         The <code>Map</code> will be populated with the name value pairs of the HTML form's content.
         *                      It works pretty much like the <code>HttpServletRequest</code> class except it can handle multipart/form-data.
         */
        public void read( ServletRequest request, Map map ) throws IOException
        {
            byte[] bytes = new byte[ 2048 ];
            int state = 0;
            int eof = 0;        /* Get the separator for this request's form data.  It is necessary for parsing this request's form data. */
            String boundary = request.getContentType();
            int pos = boundary.indexOf( "=" );
            boundary = boundary.substring( pos + 1 );
            boundary = "--" + boundary;        String fieldName = null;
            String fieldValue = null;        ServletInputStream sStream = request.getInputStream();        ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();        eof = sStream.readLine( bytes, 0, 2048 );        map.clear();
            state = 0;        while( -1 != eof )
            {
                String filter = new String( bytes, 0, eof );            if( filter.startsWith( boundary ) )
                {
                    state = READY;                if( null != fieldName )
                    {
                        if( null != fieldValue )
                        {
                            Object o = map.get( fieldName );
                            Object val = fieldValue.substring( 0, fieldValue.length() - 2 );
                            if( null == o )
                                map.put( fieldName, val );
                            else
                            {
                                if( o instanceof List )
                                    ((List)o).add( val );
                                else
                                {
                                    List list = new ArrayList();
                                    list.add( o );
                                    list.add( val );
                                    map.put( fieldName, list );
                                }
                            }
                        }
                        else if( dataBuffer.size() > 2 )
                        {
                            map.put( fieldName, dataBuffer.toByteArray() );
                        }                    fieldName = null;
                        fieldValue = null;
                        dataBuffer.reset();
                    }
                }
                else if( filter.startsWith( "Content-Disposition: form-data" ) && state == READY )
                {
                    StringTokenizer tokenizer = new StringTokenizer( filter, ";=\"" );                while( tokenizer.hasMoreTokens() )
                    {
                        String token = tokenizer.nextToken().trim();                    if( token.startsWith( "name" ) )
                        {
                            fieldName = tokenizer.nextToken().trim();
                            state = NAME;
                        }
                        else if( token.startsWith( "filename" ) )
                        {
                            state = FILENAME;
                            break;
                        }
                    }
                }
                else if( filter.equals( "\r\n" ) && state == FILENAME ) state = BINDATA;
                else if( filter.equals("\r\n" ) && state == NAME ) state = TXTDATA;
                else if( state == TXTDATA ) fieldValue = fieldValue == null ? filter : fieldValue + filter;
                else if( state == BINDATA ) dataBuffer.write( bytes, 0, eof );            eof = sStream.readLine( bytes, 0, 2048 );
            }// Parsing stops here. The Map should now contain all of the form's data.
            sStream.close();
        }    /**
         * A utility method that saves you the trouble of having to create a Map object and passing it to the other read method.
         *
         * @param   request     The ServletRequest object
         *
         * @return  A java.util.HashMap containing the name-value pairs of the HTTP POST's form data
         */
        public HashMap read( ServletRequest request ) throws IOException
        {
            HashMap hash = new HashMap();
            this.read( request, hash );
            return hash;
        }
    }