⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 multirequest.java

📁 培训考试系统代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:

  /**
   * 带最大文件长度限制上传。如果因文件超长,本方法确保此时写入输出流的数据长度
   * 刚好为maxFileSize个字节。允许再次调用upload()方法继续超长部分的数据。超长
   * 文件不上传完,将获得不了后续参数。
   * @param os 文件写入的流。
   * @param maxFileSize 最大文件长度,整数最大值大约是2G,应该足够了。
   * @return 成功返回文件大小,出错返回小于0的错误号,其中:
   *         文件超过最大限制返回-1;上传过程中流结束返回-2;
   *         上传文件前流已经结束返回-3。
   * @throws IOException 从请求中读数据或往输出流里写数据时出现异常。
   */
  public int upload(OutputStream os,int maxFileSize) throws IOException {
    int fileLength = 0;
    int safeLength = BUFFER_SIZE - boundary.length;
    if (inputFinished)
      return -3;
    for (;;) { //循环从输入流中读,往输出流里写,直到读到边界为止
      int n = fillTo(boundary);
      if (n==-1) { //缓冲区被读满
        if (fileLength+safeLength > maxFileSize) { //将会超大
          safeLength = maxFileSize - fileLength;
          os.write(buffer,0,safeLength);
          moveFront(safeLength);
          return -1;
        } else { //不会超大
          os.write(buffer,0,safeLength);
          moveFront(safeLength);
          fileLength += safeLength;
        }
      } else if (n==-2) { //输入流已经结束
        return -2;
      } else { //读到边界
        if (fileLength+safeLength > maxFileSize) { //将会超大
          safeLength = maxFileSize - fileLength;
          os.write(buffer,0,safeLength);
          moveFront(safeLength);
          return -1;
        } else { //不会超大
          os.write(buffer,0,n);
          moveFront(n+boundary.length);
          fileLength += n;
          filename = null;
          fileFullName = null ;
          while (parseNext()); //解析下一个参数直到不能解析为止
        }
        return fileLength;
      }
    } //for(;;)结束
  }

  /**
   * 解析下一个参数片段,并将解析出的参数名、参数值放到参数哈希表中,若当前位置
   * 指向一个上传文件的内容,则什么也不做,直接返回。也就是说必须处理完上传文件
   * 才能继续对其后面的内容进行解析。
   * @return 成功解析出下一个片段,则返回true;
   *         输入流结束或遇到一个需要上传的文件,则不做任何处理,直接返回false。
   * @throws IOException 读取请求输入流出现异常。
   * @exception IndexOutOfBoundsException 协议格式不符合约定导致解析错误。
   */
  private boolean parseNext() throws IOException{
    if (inputFinished || (filename!=null && !filename.equals(""))) //已经不能解析了
      return false;
    String head = readString(HEAD_END); //读取片段头
    if (head==null)
      return false;

    //从片段头中获得参数名
    int nameBegin = head.indexOf("name=\"");
    int nameEnd = head.indexOf((int)'\"',nameBegin+6);
    String name = head.substring(nameBegin+6,nameEnd);
    String value; //用来存放参数值

    //判断是否文件类型
    int fileBegin = head.indexOf("filename=\"");
    if (fileBegin<0) { //不是文件类型,取出片段体作为参数值
      value = readString(boundary);
    } else { //是文件类型的参数,将文件名作为参数值
      int fileEnd = head.indexOf((int)'\"',fileBegin+10);
      value = head.substring(fileBegin+10,fileEnd);

      //保存文件的全路径名
      this.fileFullName = value ;
      //去掉文件名中的路径
      int f = value.lastIndexOf((int)'/');
      if (f<0)
        f = value.lastIndexOf((int)'\\');
      if (f<0)
        f = value.lastIndexOf((int)':');
      if (f>=0)
        value = value.substring(f+1);
      filename = value;
    }

    //将参数加入列表
    List values = (List) parameters.get(name);
    if (values==null) { //如果还没有该名称的参数,则先建立一个空列表
      values = new ArrayList();
      parameters.put(name,values);
    }
    values.add(value);
    return true;
  }

  /**
   * 读输入流中的数据直到填满缓冲区,或者遇到指定的边界标记,或者输入流结束。
   * 如果读取前在当前缓冲中找到边界标记,则不做任何事情,直接返回标记的位置。
   * @param endFlag边界标记。
   * return -1 缓冲区满;-2 输入流结束;遇到的第一个边界的位置。
   */
  private int fillTo(byte[] endFlag) throws IOException{
    boolean notFind = true;
    int flagLength = endFlag.length;
    int position = 0; //已经搜索过的位置
    for(;;) { //循环查找

      //从position到数据结束前范围内寻找边界
      for (; position<dataLength-flagLength; position ++) {
        notFind=false;

        //和边界进行匹配
        for (int i=flagLength-1;i>=0;i--) { //倒着找比较快

          //只要有一个字节不相等position就不是匹配位置,进入position的下一个循环
          if (buffer[position+i]!=endFlag[i]) {
            notFind=true;
            break;
          }
        }
        if (!notFind) break; //找到了
      }
      //当前缓冲区已经搜索完成

      if (notFind) { //如果没找到
        if (dataLength<BUFFER_SIZE) { //没找到,并且缓冲区没满了

          //读一段数据到缓冲区
          int n = requestStream.read(buffer,dataLength,BUFFER_SIZE-dataLength);
          if (n<0) {//没找到并且缓冲区没满,读时发现输入流结束了
            inputFinished = true;
            return -2;
          }
          dataLength += n;
          continue; //读入了新数据,重新查找
        } else //缓冲区满了并且没找到
          return -1;
      } else //如果找到了,则返回找到的位置
        return position;
    }
  }

  /**
   * 将缓冲区中数据前移n字节,若n>=dataLength则将dataLength设置为0。
   * @param n 前移多少字节。
   */
  private void moveFront(int n) {
    if (n>=dataLength)
      dataLength = 0;
    else {
      System.arraycopy(buffer,n,buffer,0,dataLength-n);
      dataLength -= n;
    }
  }

  /**
   * 读取以endFlag结尾的数据转换成字符串(不包括结束标记本身),
   * 并将缓冲中内容连同结束标记全部清除。
   * @param endFlag 结束标记。
   * @return 返回读到的字符串,如果流结束仍没读到endFlag则返回null。
   * @throws IOException 读取请求数据流时出现异常。
   */
  private String readString(byte[] endFlag) throws IOException {
    List result = new LinkedList(); //保存读出的字节
    int flagLen = endFlag.length;
    int safeLen = BUFFER_SIZE - flagLen;
    int end; //结束标记在缓冲区中的位置
    for(;;){ //循环读
      end = fillTo(endFlag); //申请读到结束标记
      if (end<=-2) { //没读到结束标记输入流就已经结束
        return null;
      } else { //读到结束标记或缓冲区满
        byte[] oldBuffer = buffer; //保存旧缓冲区
        buffer = new byte[BUFFER_SIZE];//创建新缓冲区
        result.add(oldBuffer);
        if (end < 0) { //读到缓冲区满
          System.arraycopy(oldBuffer,safeLen,buffer,0,flagLen);
          dataLength=flagLen;
        } else { //读到结束标记
          int remainLength = dataLength-end-flagLen;
          System.arraycopy(oldBuffer,end + flagLen,buffer,0,remainLength);
          dataLength=remainLength;
          break;
        }
      }
    } //for(;;)结束

    //将列表中的多个数组合并成单个数组,并转换成字符串
    byte[] single = new byte[(result.size()-1)*(safeLen)+end];
    int index = 0;
    for (Iterator i = result.iterator(); i.hasNext();index++) {
      byte[] item = (byte[]) i.next();
      if (i.hasNext()) //不是最后一个
        System.arraycopy(item,0,single,index*safeLen,safeLen);
      else
        System.arraycopy(item,0,single,index*safeLen,end);
    }

    //使用request的编码字符集转换  -- modify by 黎新朝
    return new String(single ,this.charset); //转换成字符串
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -