More efficient way than creating scanner of .txt file twice I am working on a simple personal project to build a Hoffman Tree. In my constructor, shown below, I am reading in a file, creating HoffmanNodes that represent each char in the file then I got through the file to encode it. I need to create a Scanner to go through the file once to find all the chars and their frequency, then I recreate the scanner of the same file and go through it again to encode it. 

I have tried to do some research to find a more efficient way to do this, and I am coming up short. Is there an easier way to do this?

public HoffmanCoding(File inFile) {

    Scanner in = createScanner(inFile);
    //Check empty file
    if (in.hasNextLine() == false) {
        throw new IllegalArgumentException("Can not encode an empty file");
    }

    //Create a HashMap that holds all the HoffmanNodes in the HoffmanTree
    nodeHashMap = buildNodeHashMap(in);
    //Use the HashMap to create a Priority Que that I then can use to make the tree
    PriorityQueue&lt;HoffmanTreeNode&gt; allNodes = new PriorityQueue&lt;&gt;(nodeHashMap.values());
    //Build the HoffmanTree
    this.rootOfHoffmanTree = buildHoffmanTree(allNodes);
    //Assign a code to all the nodes based on their position in the tree.
    assignCode(this.rootOfHoffmanTree, "");

    // Recreate scanner reset it to the begging of the file
    in = createScanner(inFile);
    //Encode and Decode the message.
    this.encodedMessage = encodeMessage(in);
    in.close();
    this.decodedMessage = decodeMessage(this.encodedMessage);
}
I'd be very skeptical about making any changes to the current code you have when it comes to creating the scanners. However, I do want to indicate that reopening a file while it is still open is probably not a good idea. So I'd use a try-with-resources when you create the Scanner instances. I don't think reopening a file is so resource intensive that it needs to be avoided.

However, file access is commonly performed using a file pointer, and that file pointer can be reset. The question is then how to make a FileInputStream aware of that. This can be done by asking for the file channel (introduced with Java NIO2) and then setting the position on that.

So if we read the documentation of FileInputStream#getChannel() we get:


  Reading bytes from this stream will increment the channel's position. Changing the channel's position, either explicitly or by reading, will change this stream's file position.


Ah! Right what we are after, so here is code that leaves the file open:

try (FileInputStream fis = new FileInputStream(inFile)) {
    Scanner scanner1 = new Scanner(fis);
    System.out.println(scanner1.nextLine());

    fis.getChannel().position(0L);

    Scanner scanner2 = new Scanner(fis);
    // prints the same line!
    System.out.println(scanner2.nextLine());

    // the underlying file stream will be closed anyway, but yeah...
    scanner2.close();
    scanner1.close();
}


Reusing a scanner itself doesn't work. The reason is that Scanner instances cache data, which means that that data is not present anymore in any underlying stream. This is why no such functionality is supplied. Scanner is not a very heavy-weight component to instantiate, so I guess that's all right.

The above code is pretty ugly because how Java handles close(). Any call to Scanner.close() - implicit or explicit - will also close the underlying FileInputStream. That's of course not very useful in this scenario.

An ugly hack is to create a FilterInputStream-based decorator that simply forwards everything and then simply doesn't call close on the underlying stream. That way you can close the scanners without closing the underlying FileInputStream. But yeah, just as yucky as above code.

The fact that it is possible to re-read the file without re-opening it is not sufficient reason to use tricks like above. If you close the file then the file handle is released and when reopening the file is probably still cached.



I don't know enough about your application to know if rewriting your code to use Java NIO directly makes sense. Scanner was added to Java to make it easy to parse simple input, it was not meant to parse complex files, as the first line of documentation shows:


  A simple text scanner which can parse primitive types and strings using regular expressions.




Your code looks OK-ish. I'm very worried about the number and use of fields though. Generally a lot of fields is a red flag when it comes to class design. The fact that all the processing is performed in the constructor is not a good sign either. The separate part of encoding should take place in a separate method, which would make above solution even harder to apply.