我的建议是:不要创建 ,只需使用您已经从该方法获得的字节数组即可。这应该足以创建一个 .ByteArrayInputStream
getBytes
ServletInputStream
最基本的解决方案
不幸的是,aksappy的答案只会覆盖该方法。虽然这在Servlet API 3.0及更低版本中可能就足够了,但在Servlet API的更高版本中,您还需要实现三种方法。read
以下是我对该类的实现,尽管它变得很长(由于Servlet API 3.1中引入了新方法),但您可能需要考虑将其分解为嵌套甚至顶级类。
final byte[] myBytes = myString.getBytes("UTF-8");
ServletInputStream servletInputStream = new ServletInputStream() {
private int lastIndexRetrieved = -1;
private ReadListener readListener = null;
@Override
public boolean isFinished() {
return (lastIndexRetrieved == myBytes.length-1);
}
@Override
public boolean isReady() {
// This implementation will never block
// We also never need to call the readListener from this method, as this method will never return false
return isFinished();
}
@Override
public void setReadListener(ReadListener readListener) {
this.readListener = readListener;
if (!isFinished()) {
try {
readListener.onDataAvailable();
} catch (IOException e) {
readListener.onError(e);
}
} else {
try {
readListener.onAllDataRead();
} catch (IOException e) {
readListener.onError(e);
}
}
}
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
}
return i;
} else {
return -1;
}
}
};
添加预期的方法
根据您的要求,您可能还希望重写其他方法。正如 romfret 所指出的,建议重写某些方法,例如 and 。如果不实现它们,流将始终报告有 0 个字节可供读取,并且该方法不会对流的状态执行任何操作。您可能无需覆盖 即可逃脱,因为默认实现只会调用多次。close
available
close
skip
read
@Override
public int available() throws IOException {
return (myBytes.length-lastIndexRetrieved-1);
}
@Override
public void close() throws IOException {
lastIndexRetrieved = myBytes.length-1;
}
编写更好的关闭方法
不幸的是,由于匿名类的性质,您将很难编写有效的方法,因为只要流的一个实例没有被Java垃圾收集,它就会维护对字节数组的引用,即使流已关闭也是如此。close
但是,如果将类分解为嵌套类或顶级类(甚至是具有构造函数的匿名类,您可以从定义它的行调用该类),则可以是非最终字段而不是最终局部变量,并且可以添加如下行:myBytes
myBytes = null;
到您的方法,这将允许 Java 释放字节数组占用的内存。close
当然,这将需要您编写一个构造函数,例如:
private byte[] myBytes;
public StringServletInputStream(String str) {
try {
myBytes = str.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("JVM did not support UTF-8", e);
}
}
标记和重置
您可能还希望覆盖 ,如果要支持标记/重置。我不确定它们是否真的被你的容器调用过。mark
markSupported
reset
private int readLimit = -1;
private int markedPosition = -1;
@Override
public boolean markSupported() {
return true;
}
@Override
public synchronized void mark(int readLimit) {
this.readLimit = readLimit;
this.markedPosition = lastIndexRetrieved;
}
@Override
public synchronized void reset() throws IOException {
if (markedPosition == -1) {
throw new IOException("No mark found");
} else {
lastIndexRetrieved = markedPosition;
readLimit = -1;
}
}
// Replacement of earlier read method to cope with readLimit
@Override
public int read() throws IOException {
int i;
if (!isFinished()) {
i = myBytes[lastIndexRetrieved+1];
lastIndexRetrieved++;
if (isFinished() && (readListener != null)) {
try {
readListener.onAllDataRead();
} catch (IOException ex) {
readListener.onError(ex);
throw ex;
}
readLimit = -1;
}
if (readLimit != -1) {
if ((lastIndexRetrieved - markedPosition) > readLimit) {
// This part is actually not necessary in our implementation
// as we are not storing any data. However we need to respect
// the contract.
markedPosition = -1;
readLimit = -1;
}
}
return i;
} else {
return -1;
}
}