4

about the IO, I have two questions.

A. In a tutorial and some StackOverflow answers, they claimed that FileInputStream is not buffered. is that true ?

The following code use FileInputStream to read data into a byte array(1024 bytes)

class Test {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("./fos.txt");
        FileOutputStream fos = new FileOutputStream("./copy.txt");

        byte[] buffer = new byte[1024];   // Is this a buffer ? 

        int len;
        while ((len = fis.read(buffer))!= -1) {
            fos.write(buffer);
        }

        fos.close();
        fis.close();
    }
}

From the API, there is one line:

public int read(byte b[]) throws IOException

  • @param b: the buffer into which the data is read.

B. If they are both buffered, they both put the data into the buffer, and fetch the data from the buffer, where exactly is the place that makes BufferedInputStream faster than FileInputStream?

Thank you

Community
  • 1
  • 1
Reacher
  • 356
  • 4
  • 16
  • 6
    a BufferedInputStream has an *internal* buffer. If you read bytes one by one, it will not read bytes one by one from the underlying source stream, but will read them by batches, and store the last batch in a buffer. The javadoc is your friend. https://docs.oracle.com/javase/8/docs/api/java/io/BufferedInputStream.html – JB Nizet Oct 04 '18 at 06:07
  • 1
    Your benchmark is not valid - it doesn't adhere to any of the best practices of writing such benchmarks in Java. I would disregard the numbers. – Boris the Spider Oct 04 '18 at 06:12
  • @JBNizet , thank you, but we do can call the varaible `buffer` a buffer, am i correct? – Reacher Oct 04 '18 at 06:24
  • Yes, so what? That doesn't make FileInputStream buffered like a BufferdInputStream is. It just has a method that accepts an external buffer as argument. – JB Nizet Oct 04 '18 at 06:26
  • Relevant: https://stackoverflow.com/q/18600331/1233251 – E_net4 Oct 04 '18 at 08:04
  • Your comment flag has been declined. Please read about [how to flag comments](https://meta.stackoverflow.com/questions/373801/when-is-a-comment-hostile-or-unfriendly-educating-newer-users-how-to-flag-comm). @Ruizhi –  Oct 04 '18 at 08:45

2 Answers2

6

In a tutorial and some StackOverflow answers, they claimed that FileInputStream is not buffered. is that true ?

Writing to any file is buffered by the OS, however, in this case, it is not buffered by Java. Buffering helps when you perform many small writes, a 1 KB write is not small.

The following code use FileInputStream to read data into a byte array(1024 bytes)

    int len;
    while ((len = fis.read(buffer))!= -1) {
        fos.write(buffer);
    }

This loop is broken as it assumes you always read exactly 1024 bytes and the file length is always a multiple of 1024.

Instead, you should write the length that was read.

    for (int len; (len = fis.read(buffer))!= -1; )
        fos.write(buffer, 0, len);

If they are both buffered, they both put the data into the buffer, and fetch the data from the buffer, where exactly is the place that makes BufferedInputStream faster than FileInputStream?

In this case, the BufferedInputStream will use an 8 KB buffer by default. This will reduce the number of system calls by up to a factor of 8, however, it would be much simpler in your case to just use an 8 KB byte[] and save some redundant copies.

public static void main(String[] args) throws IOException {
    try (FileInputStream fis = new FileInputStream("./fos.txt");
         FileOutputStream fos = new FileOutputStream("./copy.txt")) {

        byte[] buffer = new byte[8 << 10]; // 8 KB
        for (int len; (len = fis.read(buffer)) != -1; )
            fos.write(buffer, 0, len);
    }
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

It is true that FileInputStream is not buffered but it does provide limited buffer like abilities when reading.

The biggest difference is that BufferedInputStream supports mark() and reset() where as FileInputStream doesn't.

mark(int readlimit) will allow you to set a position in the stream for later use. reset() will set your position in the stream to what specified in mark(int readLimit)

To support mark() and reset() BufferedInputStream has to maintain an internal buffer where as FileInputStream will not.

Richard Stokes
  • 385
  • 3
  • 11