How to use BufferedReader and BufferedWriter to interact with a process's console using processBuilder

37 Views Asked by At

I have built a game of text based BlackJack and am coding a bot to play the game and record the results. I have successfully launched the game and read the initial data from the console however once the bot decides his move I cannot either write that into the Blackjack console or retrieve the response that the game provides.

Here is the code so far:

public static void main(String[] args) {
        try {
            ProcessBuilder builder = new ProcessBuilder("java","app.App");
            builder.directory(new File("C:\\Users\\damon\\OneDrive\\school\\code\\BlackJack"));
            builder.redirectErrorStream(true);
            Process process = builder.start();

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
                    String line1 = reader.readLine(); // Player's total
                    String line2 = reader.readLine(); // Player's cards
                    String line3 = reader.readLine(); // Can split
                    String line4 = reader.readLine(); // Dealer's total
                    String line5 = reader.readLine(); // Dealer's cards
                    // Process the lines to extract and store the data
                    int playersTotal = Integer.parseInt(line1);
                    String[] playerCards = line2.split(" ");
                    boolean canSplit = line3.equals("s");
                    int dealersTotal = Integer.parseInt(line4);
                    String[] dealerCards = line5.split(" ");
                    Stratergy strat=new Stratergy(playersTotal, playerCards[0], canSplit,dealersTotal);
                    writer.write(strat.suggestAction()+"\n");
                    System.out.println(line1+"\n"+line2+"\n"+line3+"\n"+line4+"\n"+line5+"\n"+strat.suggestAction());
                    System.out.println(reader.readLine());          
            reader.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
1

There are 1 best solutions below

2
rzwitserloot On

As the word 'buffer' suggests, BufferedWriter buffers.

That means someBufferedWriter.write("Hello!") does absolutely nothing at all. It just.. shoves "Hello!" in the buffer. It's purely a memory operation. Not a thing happens to the underlying stream.

That's the point - many raw OS level resources have the property that interacting with them is expensive, and, tends to work not so much as a continuous stream of data, but instead as a sequence of blocks which are reconstituted back into a continuous stream on the other side. With the obvious conclusion that sending things 1 byte at a time is incredibly inefficient (as in, thousands of times slower) vs just sending data in full blocks.

That's why it works that way - if you need that buffering thing, use it. If you don't, then don't. Or, if you somehow insist on using BufferedWriter here, the flush() call tells BW to send its buffer now. So, add that. Right after your .write call, immediately call flush(). Until you do (or until the BW object decides its buffer is full enough to fire off a block, which just that little command string definitely isn't going to fill up), that java process you are starting receives no data whatsoever.

Note that instead of PB you can just re-assign sysin and sysout (System.setIn / System.setOut) and then call app.App.main(args) yourself. Saves a JVM invocation, and is probably a lot simpler than futzing about with ProcessBuilder here. But, once you add that flush(), things will work fine. Or if they still don't, the communications channel between the 2 processes is no longer the problem.