脚本巴巴 www.jiaoben88.com

request.getinputstream只能读取一次的解决方法

发布时间:2017-03-05 20:36:59编辑:脚本巴巴

本文主要为大家分享下request.getinputstream只能读取一次的解决方法,如果有朋友正好碰到此问题可以参考解决下。

首先,我们复习一下InputStream read方法的基础知识,

Java InputStream read方法内部有一个,postion,标志当前流读取到的位置,每读取一次,位置就会移动一次,如果读到最后,InputStream.read方法会返回-1,标志已经读取完了,如果想再次读取,可以调用inputstream.reset方法,position就会移动到上次调用mark的位置,mark默认是0,所以就能从头再读了。

当然,能否reset是有条件的,它取决于markSupported,markSupported() 方法返回是否可以mark/reset

我们再回头看request.getInputStream

request.getInputStream返回的值是ServletInputStream,查看ServletInputStream源码发现,没有重写reset方法,所以查看InputStream源码发现marksupported 返回false,并且reset方法,直接抛出异常。

InputStream.Java

public boolean markSupported() {  
           return false;  
       }  


 

public synchronized void reset() throws IOException {  
           throw new IOException("mark/reset not supported");  
       }  

综上所述,在request.getinputstream读取一次后position到了文件末尾,第二次就读取不到数据,由于无法reset(),所以,request.getinputstream只能读取一次。

总结:

这个问题最根本还是对java IO的read、reset方法的深入理解,尤其是read方法的内部实现原理。

附ServletInputStream.java源码
 

/*  
     * Licensed to the Apache Software Foundation (ASF) under one or more  
     * contributor license agreements.  See the NOTICE file distributed with  
     * this work for additional information regarding copyright ownership.  
     * The ASF licenses this file to You under the Apache License, Version 2.0  
     * (the "License"); you may not use this file except in compliance with  
     * the License.  You may obtain a copy of the License at  
     *  
     *     http://www.apache.org/licenses/LICENSE-2.0  
     *  
     * Unless required by applicable law or agreed to in writing, software  
     * distributed under the License is distributed on an "AS IS" BASIS,  
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
     * See the License for the specific language governing permissions and  
     * limitations under the License.  
     */  
    package javax.servlet;  
      
    import java.io.IOException;  
    import java.io.InputStream;  
      
    /**  
     * Provides an input stream for reading binary data from a client request,  
     * including an efficient <code>readLine</code> method for reading data one line  
     * at a time. With some protocols, such as HTTP POST and PUT, a  
     * <code>ServletInputStream</code> object can be used to read data sent from the  
     * client.  
     * <p>  
     * A <code>ServletInputStream</code> object is normally retrieved via the  
     * {@link ServletRequest#getInputStream} method.  
     * <p>  
     * This is an abstract class that a servlet container implements. Subclasses of  
     * this class must implement the <code>java.io.InputStream.read()</code> method.  
     *  
     * @see ServletRequest  
     */  
    public abstract class ServletInputStream extends InputStream {  
      
        /**  
         * Does nothing, because this is an abstract class.  
         */  
        protected ServletInputStream() {  
            // NOOP  
        }  
      
        /**  
         * Reads the input stream, one line at a time. Starting at an offset, reads  
         * bytes into an array, until it reads a certain number of bytes or reaches  
         * a newline character, which it reads into the array as well.  
         * <p>  
         * This method returns -1 if it reaches the end of the input stream before  
         * reading the maximum number of bytes.  
         *  
         * @param b  
         *            an array of bytes into which data is read  
         * @param off  
         *            an integer specifying the character at which this method  
         *            begins reading  
         * @param len  
         *            an integer specifying the maximum number of bytes to read  
         * @return an integer specifying the actual number of bytes read, or -1 if  
         *         the end of the stream is reached  
         * @exception IOException  
         *                if an input or output exception has occurred  
         */  
        public int readLine(byte[] b, int off, int len) throws IOException {  
      
            if (len <= 0) {  
                return 0;  
            }  
            int count = 0, c;  
      
            while ((c = read()) != -1) {  
                b[off++] = (byte) c;  
                count++;  
                if (c == '\n' || count == len) {  
                    break;  
                }  
            }  
            return count > 0 ? count : -1;  
        }  
      
        /**  
         * Returns <code>true</code> if all the data has been read from the stream,  
         * else <code>false</code>.  
         *  
         * @since Servlet 3.1  
         */  
        public abstract boolean isFinished();  
      
        /**  
         * Returns <code>true</code> if data can be read without blocking, else  
         * <code>false</code>. If this method is called and returns false, the  
         * container will invoke {@link ReadListener#onDataAvailable()} when data is  
         * available.  
         *  
         * @since Servlet 3.1  
         */  
        public abstract boolean isReady();  
      
        /**  
         * Sets the {@link ReadListener} for this {@link ServletInputStream} and  
         * thereby switches to non-blocking IO. It is only valid to switch to  
         * non-blocking IO within async processing or HTTP upgrade processing.  
         *  
         * @param listener  The non-blocking IO read listener  
         *  
         * @throws IllegalStateException    If this method is called if neither  
         *                                  async nor HTTP upgrade is in progress or  
         *                                  if the {@link ReadListener} has already  
         *                                  been set  
         * @throws NullPointerException     If listener is null  
         *  
         * @since Servlet 3.1  
         */  
        public abstract void setReadListener(ReadListener listener);  
    }  
上一篇:jsp中request接收中文参数乱码问题解决办法
下一篇:jsp页面经servlet后运行成乱码

相关文章