BufferedReader 中的标记和重置是啥?
Posted
技术标签:
【中文标题】BufferedReader 中的标记和重置是啥?【英文标题】:What are mark and reset in BufferedReader?BufferedReader 中的标记和重置是什么? 【发布时间】:2012-01-04 14:52:50 【问题描述】:我想知道BufferedReader
的mark()
和reset()
方法是什么?我该如何使用它们?我阅读了 Javadoc,但作为初学者我无法理解它。
【问题讨论】:
【参考方案1】:流的mark
和reset
方法提供了一种在流中向后跳转并重新读取数据的方法。
当您在BufferedReader
上调用mark()
时,它将开始将您从该点读取的数据向前保存在其内部缓冲区中。当您调用reset()
时,它将跳回到流的标记位置,因此下一个read()
s 将由内存缓冲区满足。当您读取该缓冲区的末尾时,它将无缝返回读取新数据。 BufferedInputStream
的工作方式相同。
mark
的 int 参数告诉它您希望能够后退的最大字符数(对于 BufferedReader
)或字节数(对于 BufferedInputStream
)。如果您在标记位置之后读取的数据过多,则标记可能会“无效”,并且调用reset()
将失败并出现异常。
一个小例子:
BufferedReader r = new BufferedReader(new StringReader(
"Happy Birthday to You!\n" +
"Happy Birthday, dear " + System.getProperty("user.name") + "!"));
r.mark(1000); // save the data we are about to read
System.out.println(r.readLine()); // read the first line
r.reset(); // jump back to the marked position
r.mark(1000); // start saving the data again
System.out.println(r.readLine()); // read the first line again
System.out.println(r.readLine()); // read the second line
r.reset(); // jump back to the marked position
System.out.println(r.readLine()); // read the first line one final time
在该示例中,我将StringReader
包装在BufferedReader
中以获得readLine()
方法,但StringReader
s 已经支持mark
和reset
!从 内存中 数据源读取的流通常支持 mark
和 reset
本身,因为它们已经在内存中拥有所有数据,因此它们很容易再次读取。从文件或管道或网络套接字读取的流自然不支持mark
和reset
,但您始终可以将该功能添加到任何流中,方法是将其包装在BufferedInputStream
或BufferedReader
中。
【讨论】:
【参考方案2】:mark()
标记流中的特定点,reset()
将流重置为最新标记。这些方法提供了book-marking
功能,允许您在流中提前读取以检查即将出现的数据。
来自documentation:
mark() 方法在输入中标记一个位置,流可以通过以下方式“重置”到该位置 调用 reset() 方法。参数readLimit是个数 之前设置标记后可以从流中读取的字符 标记无效。例如,如果使用 read 调用 mark() 限制为 10,然后从流中读取 11 个字符的数据 在调用 reset() 方法之前,标记无效并且 流对象实例不需要记住标记。注意 这种方法可以记住的字符数可以是 大于内部读取缓冲区的大小。它也不是 依赖于支持标记/重置的从属流 功能。
【讨论】:
你也可以用它来简单地标记开始并回到开始重新读取缓冲区吗?例如,如果您想读取文件两次。一次获得上下文,回到开头,然后再读一遍? 它的参数是什么?【参考方案3】:Reader::mark(int readLimit)
文档说:
在此阅读器中设置标记位置。参数 readLimit 表示 在标记失效之前可以读取多少个字符。 调用 reset() 会将阅读器重新定位到标记的位置 如果没有超过 readLimit。
例子:
import java.io.*;
import static java.lang.System.out;
public class App
public static final String TEST_STR = "Line 1\nLine 2\nLine 3\nLine 4\n";
public static void main(String[] args)
try (BufferedReader in = new BufferedReader(new StringReader(TEST_STR)))
// first check if this Reader support mark operation
if (in.markSupported())
out.println(in.readLine());
in.mark(0); // mark 'Line 2'
out.println(in.readLine());
out.println(in.readLine());
in.reset(); // reset 'Line 2'
out.println(in.readLine());
in.reset(); // reset 'Line 2'
out.println(in.readLine());
in.mark(0); // mark 'Line 3'
out.println(in.readLine());
in.reset(); // reset 'Line 3'
out.println(in.readLine());
out.println(in.readLine());
catch (IOException e)
e.printStackTrace();
输出:
Line 1
Line 2
Line 3
Line 2
Line 2
Line 3
Line 3
Line 4
【讨论】:
你怎么能打电话给reset()
?我认为如果您mark()
的读取限制为 0,则一旦读取一个字符,标记就会变得无效并且无法调用重置。你能解释一下你的答案吗?
@snooze92 只是为了运行这个示例并尝试更改mark
方法中的markLimit
参数。您将始终得到相同的结果。另请参阅类似示例:1、2。我实际上想对 SO 提出问题,有人给了我一个解释。
在运行了更多我自己的示例之后,我对mark(readAheadLimit)
/reset()
机制有了更好的理解。基本上,mark
方法只是在 当前缓冲区 中标记一个点,reset
让您回到那个标记点。问题是,它并不意味着在文件或流中标记点,因为它需要增加缓冲区大小以保持访问标记点的可能性。这就是为什么一个应该使用一个相对小于缓冲区大小的限制。
截至 “为什么示例在限制为 0(或任何限制)的情况下工作” 也很容易解释。默认缓冲区大小(在两个示例中都使用)是 4096。示例中使用的字符串非常小,以至于一旦创建 BufferedReader,它就会在第一个缓冲区中完全读取。稍后它不会再读任何内容,因此根本没有使用 limit 参数......这使得这个例子变得毫无意义和令人困惑的恕我直言。稍微更改示例以在 BufferedReader 构造函数中添加非常小的缓冲区大小(例如 2 或 3)将开始引发无效标记异常。
@snooze92 感谢您的解释。为您的 cmets 点赞。【参考方案4】:
阅读器界面不让你返回,你可以阅读。另一方面,BufferedReader 创建一个缓冲区,因此您可以在读取时返回一点。这就是这些方法的用途。
使用 mark() 方法,您可以在某个位置上放置一个“标记”,然后您可以继续阅读。一旦你意识到你想要返回你使用 reset() 的标记位置。从那时起,您再次读取相同的值。你可以用它做任何你想做的事情。
【讨论】:
【参考方案5】:假设您在 BufferReader = "123456789" 中有以下字符,如果您在相对于 '5' 字符的位置 4 进行标记,然后重置 BufferReader,您将得到 12345。
【讨论】:
这是一半的答案,什么是重置? 嘿给出了正确的答案。重置只是将指向要读取的字符的指针带到它被标记的位置。【参考方案6】:这是一个例子。
int bufferSize = 4;
int readLimit = 4
ByteArrayInputStream byteInputStream = new ByteArrayInputStream("123456789abcdef".getBytes());
try(BufferedInputStream bufferedInputStream = new BufferedInputStream(byteInputStream, bufferSize))
bufferedInputStream.mark(readLimit);
System.out.print((char) bufferedInputStream.read());//byte1
System.out.print((char) bufferedInputStream.read());//byte2
System.out.print((char) bufferedInputStream.read());//byte3
System.out.print((char) bufferedInputStream.read());//byte4
bufferedInputStream.reset();
System.out.print((char) bufferedInputStream.read());//byte5
// Using this next reset() instead of the first one will throw an exception
// bufferedInputStream.reset();
System.out.print((char) bufferedInputStream.read());
System.out.print((char) bufferedInputStream.read());
System.out.print((char) bufferedInputStream.read());
输出:12341234
对于readLimit
、here's 来说是一个很好的参考。
【讨论】:
以上是关于BufferedReader 中的标记和重置是啥?的主要内容,如果未能解决你的问题,请参考以下文章
尽管 Angular 中的表单已重置,但输入字段仍标记为红色