How to rewind the file pointer correctly in Java?

Asked

Viewed 1,642 times

3

Actually the problem is quite complex, but I’m going to try to give a notion that I think will be understandable.

I have a method in an application that initializes objects to I/O in accordance with a "global context" (in reality this is a concept of my application). This method has the role of leaving objects ready for I/O operations.

public void setupSpaceIO() throws IOException {
    if(globalContext.isThereSpaceLoaded()) {
        accountReader = Files.newBufferedReader(Paths.get(globalContext.getSpace().getAccountsPath()),
                BANC_GEN_STD_CHARSET);
        accountWriter = Files.newBufferedWriter(Paths.get(globalContext.getSpace().getAccountsPath()),
                BANC_GEN_STD_CHARSET, StandardOpenOption.APPEND);
        userReader = Files.newBufferedReader(Paths.get(globalContext.getSpace().getUsersPath()),
                BANC_GEN_STD_CHARSET);
        userWriter = Files.newBufferedWriter(Paths.get(globalContext.getSpace().getUsersPath()),
                BANC_GEN_STD_CHARSET, StandardOpenOption.APPEND);
    } else {
        System.out.println("There is no space loaded!");
    }

    accountReader.mark(1);
    userReader.mark(1);
}

Writing objects work normally. But readers are the problem. Suppose they are reading a file with this content:

Linha 1
Linha 2
Linha 3

If I call a method as "readline()" it will read the first line normally. But from there it will no longer be possible to read the first line again if I so desire. Yes, in the setupSpaceIO() method are called the mark() methods that at first I am having difficulty understanding and I called them in order to leave a "rewinder" ready to be called with the reset() method. The problem is that calling the method I only get Ioexceptions.

And I didn’t see any java.io class that had a similar method to C’s Rewind().

How do I rewind the file reading pointer to the beginning of it in Java?

1 answer

4

Bufferedreader

You can rewind a Bufferedreader through the methods mark(int readAheadLimit) and reset(). It works like this, at a certain point of your reading you mark that position, and when you call reset the stream back to the marked position.

The drawback is the parameter of the mark() method that expects you to enter the maximum amount of characters you can read before rewinding, i.e., if you have a 2,000 character file you need to do:

file.mark(2000);
//código aqui para ler todas as linhas
file.reset();

You can indicate a larger size than the amount of characters in your file, however if your file is too large you may have significant performance impacts.

When calculating the buffer size mark() should create remember that each skipped line counts as two characters.

Use this possibility if you know the size of your file, even if approximately, and if it is not too large.

If you pass as argument a smaller size that the buffer will read you will receive an Ioexception.

Reference: Bufferedreader - Java SE 7

Randomaccessfile

A versatile possibility is to use the Randomaccessfile class.

He has the method seek(long pos) which allows you to point to any part of your file. Just pay attention because it waits as argument a long indicating the position in the text, and not the position of the line.

Example:

test.txt

line 1
line 2
row 3

Random java.

import java.io.IOException;
import java.io.RandomAccessFile;

public class Random {
    public static void main(String[] args) throws IOException {
        RandomAccessFile file = new RandomAccessFile("teste.txt", "r");
        String linha;
        while((linha = file.readLine()) != null) {
            System.out.println(linha);
        }
        file.seek(9); //vai para a posição 9 no teste.txt, que é o início da 2ª linha
        while((linha = file.readLine()) != null) {
            System.out.println(linha);
        }
        file.close();
    }
}

Exit:

line 1
line 2
row 3
line 2
row 3

linha 1 has 7 characters, and the line break counts as 2, which is why file.seek(9); pointed to the first character of the second line. If you want to go back to the first position of your file do file.seek(0); which would be equivalent to rewind() in C.

Reference: Randomaccessfile - Java SE 7

Completion

In JDK, there are usually many classes, each of which is an expert for a particular purpose. In the two example above is no different, you have two tools and have to know the right time to choose each one.

If you need speed and will read a file sequentially, ie you do not need to change the pointer position, the Bufferedreader is the right choice, its use is usually in very large files and you want to read it whole. Making this choice you will face the side effect that is the lack of navagability in your file. The mark() method within this class seems to me very difficult to be used with robustness, since its use is very limited, I particularly would not feel like using it because I think it does not compensate for the risk of generating an exception at runtime.

If your need is the navigability your best choice will be the Randomaccessfile class, which has the Seek() method, however it does not create a file buffer, so you will have to give up the speed in the execution of operations.

About your comment:

Thousands of I/O classes and an unnecessary learning curve to learn how to use them.

When we develop small systems, the infinity of classes that Java offers seems more like a martyrdom than a salvation, since in an application of only a few packages with a maximum of a dozen classes and a database in the MB home, the terms "speed" and "performance" practically do not need to be taken into consideration, since the difference is almost insignificant. However, in a system that has hundreds of packages and classes and constantly faces extremely intense data traffic, thousands of Java classes provide versatility that will result in an optimized system.

If your application is small, focus on what gives you the most agility at the time of development, as performance at runtime will be virtually the same. I would go from Randomaccessfile.

  • I get it. So you mean that as the file grows I need to re-insert its size to call mark() again? It’s not bad, but why does Java have to be so "cool"? Thousands of I/O classes and an unnecessary learning curve to learn how to use them.

  • @Sid is vdd, the Java learning curve is a painful thing, however try not to get too attached to the details if your application does not ask for something extremely optimized, focus on what gives you agility at the time of development. PS: I edited the answer from where it is written conclusion

Browser other questions tagged

You are not signed in. Login or sign up in order to post.