我正在使用自定义的InputStream for Scanner,并希望对其进行更改。但是在第一次读取并更改InputStream中的数据后,它会停止。
我可以修改我的代码以进行二读吗?哪种方式?
更新我将此代码与其他程序一起使用,并将其标准输入重定向到我的。因此,我需要更改System.in,并且无法重新创建扫描仪。
这是我的课程:
class CRStream extends InputStream {
private ByteArrayInputStream in;
public synchronized int read() throws IOException {
int x = in.read();
return x;
}
public synchronized int read(byte[] bytes, int off, int len) throws IOException {
return in.read(bytes, off, 1);
}
public void set(String utf8str) throws IOException{
try{
in = new ByteArrayInputStream(utf8str.getBytes(StandardCharsets.UTF_8.name()));
}
catch (UnsupportedEncodingException e){}
}
}
和使用示例
public class Main {
public static void main(String[] args) throws IOException {
CRStream in = new CRStream();
System.setIn(in);
Scanner scanner = new Scanner(System.in);
//Everything is OK
in.set("Word1 Ok Word2 Ok");
while (scanner.hasNext()){
System.out.println(scanner.next());
}
//Does not work... Prints nothing
in.set("WORD3 Ok WORD4 Ok");
while (scanner.hasNext()){
System.out.println(scanner.next());
}
}
}
这是第二个例子
一个简单的客户端程序
class ClientProgram {
public static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
System.out.println(in.next());
}
}
我用代码对其进行测试
public class Main {
public static void main(String[] args) {
CRStream in = new CRStream();
System.setIn(in);
in.set("Test1");
ClientProgram.main(new String[0]);
in.set("Test2");
ClientProgram.main(new String[0]);
}
}
它在第二次测试中落在NoSuchElementException
上。
答案 0 :(得分:0)
奇怪的是,当扫描程序可以直接从字符串中读取内容时,为什么要跳这么多圈呢?
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner("Word1 Ok Word2 Ok");
while (scanner.hasNext()){
System.out.println(scanner.next());
}
scanner = new Scanner("WORD3 Ok WORD4 Ok");
while (scanner.hasNext()){
System.out.println(scanner.next());
}
如果您希望Ok成为分隔符,则可以在扫描仪上调用useDelimiter(" Ok ")
对于实际问题,我怀疑内部扫描仪可能正在缓冲您的输入流,而没有意识到您已对其进行了切换。也许还是要制作新的扫描仪,或者将您的crinputstream重置()。也不需要用您的系统替换输入流,然后将扫描仪连接到系统中。扫描程序无需通过system.in
即可从您的输入流中读取答案 1 :(得分:0)
您可能应该包装所有获得的输入,而不是实施一个新奇的InputStream
,而只需返回要解析的字符串。这样,您的包装器类可以根据当前正在读取的内容来维护使用的Scanner
。
class TokenProvider {
Queue<Scanner> readFrom = new Deque<Scanner>();
Scanner currentScanner;
public void addSource(String string) {
readFrom.add(new Scanner(string));
}
public boolean hasNext() {
nextScanner();
return currentScanner != null && currentScanner.hasNext();
}
public String next() {
return currentScanner.next();
}
private void nextScanner() {
while (currentScanner == null || !currentScanner.hasNext()) {
if (readFrom.isEmpty()) break;
currentScanner = readFrom.poll();
}
}
}
现在您的驱动程序代码如下
TokenProvider in = new TokenProvider();
in.addSource("Word1 Ok Word2 Ok");
while (in.hasNext()){
System.out.println(in.next());
}
// all data has been iterated, but we can add more now
in.addSource("WORD3 Ok WORD4 Ok");
while (in.hasNext()){
System.out.println(in.next());
}
答案 2 :(得分:0)
扫描器保持内部状态,一旦当前源用尽,则设置标志“ sourceClosed = true”。由于将来扫描器认为尽管更改了源流,它仍然是空的,所以以后对该扫描器的任何访问都将被拒绝,因为该标志不会回滚。如果没有定制的扫描仪实现,我看不出有一种方法来规避这一问题。如果可能的话,请尝试使用新的Scanner进行每次读取,而不是进入那个兔子洞。
在第二个客户端中,不要维护静态扫描仪,
class ClientProgram {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println(in.next());
}
}