首先,我们复习一下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
综上所述,在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 * * * 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 readLine method for reading data one line * at a time. With some protocols, such as HTTP POST and PUT, a * ServletInputStream object can be used to read data sent from the * client. * * A ServletInputStream object is normally retrieved via the * {@link ServletRequest#getInputStream} method. * * This is an abstract class that a servlet container implements. Subclasses of * this class must implement the java.io.InputStream.read() 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. * * 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 true if all the data has been read from the stream, * else false . * * @since Servlet 3.1 */ public abstract boolean isFinished(); /** * Returns true if data can be read without blocking, else * false . 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); } |
忍者必须死34399账号登录版 最新版v1.0.138v2.0.72
下载勇者秘境oppo版 安卓版v1.0.5
下载忍者必须死3一加版 最新版v1.0.138v2.0.72
下载绝世仙王官方正版 最新安卓版v1.0.49
下载Goat Simulator 3手机版 安卓版v1.0.8.2
Goat Simulator 3手机版是一个非常有趣的模拟游
Goat Simulator 3国际服 安卓版v1.0.8.2
Goat Simulator 3国际版是一个非常有趣的山羊模
烟花燃放模拟器中文版 2025最新版v1.0
烟花燃放模拟器是款仿真的烟花绽放模拟器类型单机小游戏,全方位
我的世界动漫世界 手机版v友y整合
我的世界动漫世界模组整合包是一款加入了动漫元素的素材整合包,
我的世界贝爷生存整合包 最新版v隔壁老王
我的世界MITE贝爷生存整合包是一款根据原版MC制作的魔改整