Xyntell
Xyntell

Reputation: 155

Cannot use Java BufferedReader to read from a file: Stream closed

I have to create a mini-interpreter in Java for a "Toy Language" and in this project, I have to include a FileTable which is a class having as private field a HashMap<Integer, FileData>, where FileData is:

public class FileData {
    private String fileName;
    private BufferedReader fileDescriptor;

    // methods...
}

Also, I have another class OpenRFile which has a method execute(String fileName). This method creates a BufferedReader object for the given fileName and a FileData object which is added in the FileTable.

public class OpenRFile implements Statement {
    private String varName;
    private String fileName;

    // methods...
    public OpenRFile(String v, String f) {
        this.varName = v;
        this.fileName = f;
    }

    @Override
    public PrgState execute(PrgState p) {
        IDictionary<Integer, FileData> fileTable = p.getFileTable();
        IDictionary<String, Integer> symTable = p.getSymTable();

        if (symTable.contains(this.varName))
            throw new InterpreterException("Var name already exists.");

        for (Integer i: fileTable.getAll()) {
            if (fileTable.get(i).getFileName().equals(this.fileName))
                throw new InterpreterException("File is already open.");
        }

        try (BufferedReader br = new BufferedReader(new FileReader(this.fileName))) {
            Integer id = IDGenerator.generateID();
            symTable.add(this.varName, id);
            fileTable.add(id, new FileData(this.fileName, br));
        }
        catch (IOException e) {
            throw new InterpreterException(e.getMessage());
        }

        return p;
    }

    @Override
    public String toString() {
        return "OpenRFile(" + this.varName + ", " + this.fileName + ");";
    }
}

Later, in another class: ReadFile, the method execute just retrieves the FileData object from the FileTable and calls the method readLine() on the BufferedReader object, and this is the moment when I get the Steam closed error.

public class ReadFile implements Statement {
    private Expression exp;
    private String varName;

    // methods...
    public ReadFile(Expression e, String v) {
        this.exp = e;
        this.varName = v;
    }

    @Override
    public PrgState execute(PrgState p) {
        IDictionary<String, Integer> symTable = p.getSymTable();
        IDictionary<Integer, FileData> fileTable = p.getFileTable();

        Integer id = this.exp.eval(symTable);

        if (!fileTable.contains(id))
            throw new InterpreterException("File not found.");

        Integer read;

        try  {
            BufferedReader br = fileTable.get(id).getFileDescriptor();
            //BufferedReader br = new BufferedReader(new FileReader(fileTable.get(id).getFileName()));
            String line = br.readLine();
            if (line == null)
                read = 0;
            else
                read = Integer.parseInt(line);
        }
        catch (IOException e) {
            throw new InterpreterException(e.getMessage());
        }

        if (symTable.contains(this.varName))
            symTable.update(this.varName, read);
        else
            symTable.add(this.varName, read);

        return p;
    }

    @Override
    public String toString() {
        return "ReadFile(" + this.exp + ")";
    }
}

If I retrieve the fileName from the FileData object and create a new BufferedReader object, it works. But if I try to call readLine() directly on the object I already have, I get the error.

Upvotes: 2

Views: 306

Answers (1)

Bedla
Bedla

Reputation: 4919

You have created BufferedReader and FileReader in try-with-resources block. This means, that close() method was called on both directly after try block, as if there were finally{fileReader.close();bufferedReader.close()}.

Upvotes: 2

Related Questions