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      File savedFile = readAndSaveFile(in, boundary, filename,
          contentType);
      if (filename.equals(NO_FILE)) {
        files.put(name, new UploadedFile(null, null, null));
      }
      else {
        files.put(name,
          new UploadedFile(filename, savedFile, contentType));
      }
    }
    return false;  // there's more to read
  }  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
  }  protected File readAndSaveFile(MultipartInputStreamHandler in,
                                 String boundary,
                                 String filename,
                                 String contentType) throws IOException {
    OutputStream out = null;
int year = Calendar.getInstance().get(Calendar.YEAR);
int month = Calendar.getInstance().get(Calendar.MONTH) + 1;
    int date = Calendar.getInstance().get(Calendar.DATE); //i modify it from time to date,kaka
    int id = getID();
    String prefix = new Integer(year).toString() + new Integer(month).toString() + 
new Integer(date).toString() + "_" + new Integer(ID).toString();    File newFile = 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")){
      newFile = new File(dir + File.separator + prefix + filename);
      out = new MacBinaryDecoderOutputStream(
            new BufferedOutputStream(
            new FileOutputStream(newFile), 8 * 1024));
    }
    // A real file's contents are written to disk
    else {
      newFile = new File(dir + File.separator + prefix + filename);
      out = new BufferedOutputStream(new FileOutputStream(newFile), 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, "gb2312");
        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(); //set the uploaded file name for client use
setUploadedFilename(prefix + filename);    return newFile;  }  // 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;
  }to be continue

解决方案 »

  1.   

    // 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);
          // 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
        }    // 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;
      }  private synchronized int getID()
      {
        ID++;
        return ID;
      }
    }
    // A class to hold information about an uploaded file.
    //
    class UploadedFile {  private String filename;
      private File file;
      private String type;  UploadedFile(String filename, File file, String type) {
        this.filename = filename;
        this.file = file;
        this.type = type;
      }  public String getContentType() {
        return type;
      }  public String getFilename() {
        return filename;
      }  public File getFile() {
        return file;
      }
    }
    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, "ISO-8859-1"));
            sbuf.append(new String(buf, 0, result, "gb2312"));
          }
        } 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();
      }  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 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]);
          }
        }
      }
    }