bufferedinputstream中标记读取限制的用途是什么

时间:2017-02-22 10:55:58

标签: java stream bufferedinputstream

我是Java流的新手,我想阅读特定的文件内容,然后需要从头开始阅读。我创建了一个BufferedInputStream,我对BufferedInputStream.mark(int markLimit)的文档感到困惑

文档说:

public void mark(int readlimit)
  

此方法通过调用reset()方法在输入中标记流可以“重置”的位置。参数readlimit是在标记变为无效之前设置标记后可从流中读取的字节数。例如,如果调用mark()时读取限制为10,那么在调用reset()方法之前从流中读取11个字节的数据时,标记无效,并且不需要流对象实例记得那个标记。

     

请注意,此方法可以记住的字节数可能大于内部读缓冲区的大小。它也不依赖于支持标记/重置功能的从属流。

     

覆盖:   在类FilterInputStream中标记

     

参数:   readlimit - 标记变为无效之前可以读取的字节数**

我的代码是:

public class Test {
    public static void main(String[] args) throws IOException {

        File resource = new File("beforeFix.txt");          
        FileInputStream fileInputStream = new FileInputStream(resource);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        int i = bufferedInputStream.read();
        bufferedInputStream.mark(1);
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        bufferedInputStream.reset(); 
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        i = bufferedInputStream.read();
        bufferedInputStream.reset();  
    }
}

在上面的代码中,我将marklimit设置为1,但根据文档标记不会变为无效。

任何人都可以清楚地解释一下用小例子设置这个的实际目的是什么?

提前致谢

4 个答案:

答案 0 :(得分:1)

为了使重置工作并返回到您标记的位置,标记后读取的数据需要在内存中缓冲。标记时指定的值是应为此保留的内存量。

因此,如果您打算在调用reset之前读取100个字节,那么您的缓冲区需要至少100个字节,这就是您必须使用的标记。

fb.orderByChild("Lastname").equalTo('hoo').once("child_added", function(snapshot){
    console.log(snapshot.ref());
    console.log(snapshot.val());
    // var snapref = snapshot.ref();
    snapshot.ref().update({
      FirstName: 'yoyo1'      
    });  
  })

<强>更新

bufferedInputStream.mark(200); ... read no more than 200 bytes ... bufferedInputStream.reset(); // reset back to marked position 的文档看起来与实际行为不符。文档说明:

mark

然而,它看起来应该是the maximum limit of bytes that can be read before the mark position becomes invalid ,或者至少如果它们仍然支持重置到标记位置,则一旦超出读取限制就不需要丢弃标记的基础实现

答案 1 :(得分:1)

通过使用指定限制调用mark,您要求在读取到指定限制后支持重置的功能,您不会拒绝超出该限制的功能。 The specification清楚地说:

  

但是,如果在调用readlimit之前从流中读取的reset个字节超过BufferedInputStream,则根本不需要记住任何数据。

“不要求”不暗示“不允许”。规范简单地陈述了你不能期望永远工作的东西,它没有陈述你总是会失败的东西。

BufferedInputStream的情况下,很容易解释在幕后发生的事情。每个File resource = new File("beforeFix.txt"); FileInputStream fileInputStream = new FileInputStream(resource); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 1); int i = bufferedInputStream.read(); bufferedInputStream.mark(1); i = bufferedInputStream.read(); i = bufferedInputStream.read(); bufferedInputStream.reset(); // will fail 都有一个容量,default是8192,并且它总是可以重置超过其当前缓冲区容量的字节数。通过指定更高的限制,您将使其在需要时分配更大的缓冲区,以实现保证。

由于您无法查询流的当前缓冲区容量,因此只要您没有读取超过指定限制的字节数,就只能依赖重置的保证。

很容易更改您的示例以使其无法重现:

f(r,sigma,epsilon)=4*epsilon*((sigma/r)**12-(sigma/r)**6)

sigma=2.6
epsilon=5

set arrow 1 from first 3,0 to first 3, f(3,sigma,epsilon)
set arrow 2 from first 3,0 to first 2.8, f(2.8,sigma,epsilon)
set label 1 "(r_0, {/Symbol e}_0)" at first 3,0 center offset 0,1

set xlabel "Distance r_0 ({\305})" 
set ylabel "Energy E (J/mol)

set xr [2:5.2]
set yr [-6:12]

set key reverse Left at 4,5

plot for [epsi= epsilon-1:epsilon+1:1 ] f(x,sigma,epsi) title sprintf("12-6 LJ {/Symbol s}=%.1f {/Symbol e}=%.1f",sigma,epsi)

set term pngcairo enhanced 
set out "LJ.png"
replot

答案 2 :(得分:0)

请阅读以下文档以更好地理解它。我和您有同样的疑问,然后决定详细阅读它。

  1. 如果自创建流以来尚未调用方法标记,或者自上次调用该标记以来从流读取的字节数大于该最后一次调用时标记的参数,则可能抛出IOException 。
  2. 如果未抛出此类IOException,则将流重置为一种状态,以使自最近一次调用mark之后(或从文件的开始,如果尚未调用mark以来)读取的所有字节都将重新提供给read方法的后续调用者,然后再加上任何其他字节,否则这些字节在重置调用时将是下一个输入数据。

从第一点开始,现在非常清楚,不能保证会抛出IOException。因此,如果在调用mark方法后读取的字节数超出了允许的字节数(mark方法的指定参数),则此操作很冒险,因此不建议这样做。

从第二点开始,您可以了解如果不抛出IOException会发生什么。

文档链接:https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html#reset--

答案 3 :(得分:0)

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Main {
    
    static final String fileAbsolutePath = "file.txt";
    
    public static void main(String[] args) {
        // file contains 3 chars 'a', 'b', and 'c'
        try (FileInputStream fileInputStream = new FileInputStream(fileAbsolutePath);
             BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) {
            
            System.out.println((char) bufferedInputStream.read()); // prints a
            bufferedInputStream.mark(2);   // place mark at second byte
            System.out.println((char) bufferedInputStream.read()); // prints b
            System.out.println((char) bufferedInputStream.read()); // prints c
            System.out.println(bufferedInputStream.read()); // prints -1
            
            bufferedInputStream.reset();    // meaning start again from where I placed the mark
            System.out.println((char) bufferedInputStream.read()); // prints b
            System.out.println((char) bufferedInputStream.read()); // prints c
            System.out.println( bufferedInputStream.read()); // prints -1
    
        } catch (IOException ie) { ie.printStackTrace();}
    }
}