How do I rewind the file pointer correctly in Java?

3

In reality the problem is quite complex, but I will 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 fact this is a concept of my application). This method has the role of leaving ready objects 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);
}

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

Linha 1
Linha 2
Linha 3

If I call a method like "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 the mark () methods are called that at first I'm having a hard time understanding and I called them with the purpose of leaving a "rewinder" ready to be called with the reset () method. The problem is that calling the method I only get IOExceptions.

And I did not see any java.io class that had a method similar to C's rewind ().

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

    
asked by anonymous 14.06.2014 / 08:05

1 answer

4

BufferedReader

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

The drawback is the mark () method parameter that expects you to enter the maximum number of characters you can read before rewinding, that is, 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 size larger than the number of characters in your file, however if your file is too large you can have significant performance impacts.

When calculating the buffer size that 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 an argument a smaller size than the buffer will read you will get an IOException.

Reference: BufferedReader - Java SE 7

RandomAccessFile

A versatile possibility is to use the RandomAccessFile class.

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

Example:

test.txt

  

line 1
  line 2
  line 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();
    }
}

Output:

  

line 1
  line 2
  line 3
  line 2
  line 3

linha 1 has 7 characters, and the line break counts as 2, so 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, make file.seek(0); which would be equivalent to rewind() in C.

Reference: RandomAccessFile - Java SE 7

Conclusion

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

If you need speed and will read a file sequentially, that is, you do not need to change the position pointer, BufferedReader is the right choice, its use is usually in many large files and you want to read it whole. By making that choice you will face the side effect that is the lack of navigability in your file. The mark () method within this class seems to me very difficult to use with robustness, since its use is very limited, I would not particularly feel the urge to use it because I think it does not compensate the risk of generating an exception in time

If your need is airworthiness your best choice will be the RandomAccessFile class, which has the seek () method, though it does not create a file buffer, so you'll have to let go of the speed in executing the operations.

About your comment:

  

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

As we develop small systems, the plethora of classes that Java offers seem 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 house of MB , the terms "speed" and "performance" hardly need to be taken into account, since the difference is almost negligible. However, in a system that has hundreds of packages and classes and constantly faces extremely intense data traffic, Java's thousands of 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, since runtime performance will be pretty much the same. I would go from RandomAccessFile.

    
14.06.2014 / 13:25