Search code examples
javamultithreadingprocesspipejava.util.concurrent

PipedInputStream, PipedOutputStream and Process


I'm learning the java PipedInputStream/PipeOutputStream .

I'd like to read stdin (the 'Source' class below) and redirect it to an Process ( here 'grep A'), the output of Grep would be redirected to System.out.

To consumme stdout and stderr after grep, I also created a class CopyTo to redirect an inputstream to an outputstream.

import java.io.*;
class Test
    {
    private static class Source
        implements Runnable
        {
        private PipedOutputStream pipedOutputStream=new PipedOutputStream();
        private InputStream in;

            Source(InputStream in) throws IOException
                {
                this.in=in;
                }


            @Override
            public void run()
                {
                try
                    {
                    int c;
                    while((c=this.in.read())!=-1)
                        {
                        pipedOutputStream.write(c);
                        }
                    pipedOutputStream.flush();
                    pipedOutputStream.close();
                    }
            catch(Exception err)
                {
                err.printStackTrace();
                }
                }
        }

    private static class Grep
        implements Runnable
        {

        private PipedInputStream pipeInPipedInputStream;

        public Grep(Source src) throws IOException
            {
            this.pipeInPipedInputStream=new PipedInputStream(src.pipedOutputStream);
            }

            @Override
            public void run()
                {
            try {
                Process proc=Runtime.getRuntime().exec(new String[]{
                    "/bin/grep",
                    "A"});
                OutputStream os=proc.getOutputStream();


                Thread t1=new Thread(new CopyTo(proc.getErrorStream(),System.err));
                Thread t2=new Thread(new CopyTo(proc.getInputStream(),System.out));
                t1.start();
                t2.start();
                int c;
                while((c=this.pipeInPipedInputStream.read())!=-1)
                    {   
                    os.write((char)c);
                    }

                t1.join();
                t2.join();
                } 
            catch (Exception e) {
                e.printStackTrace();
                }
                }
        }

    private static class CopyTo implements Runnable
        {
        private InputStream in;
        private OutputStream out;
        CopyTo(InputStream in,OutputStream out)
            {
            this.in=in;
            this.out=out;
            }
        @Override
        public void run() {
            try {
                int c;
                while((c=in.read())!=-1)
                    {
                    out.write(c);
                    }
                }
            catch (Exception e)
                {
                e.printStackTrace();
                }
            }
        }


    public static void main(String[] args)
        {
        try
            {
            Source src=new Source(System.in);
            Thread t1=new Thread(src);
            Thread t2=new Thread(new Grep(src));
            t1.start();
            t2.start();
            }
        catch(Exception err)
            {
            err.printStackTrace();
            }
        }

    }

however, compiling and running the program produces no output (and the program is frozen).

$ javac Test.java && echo -e "A\nT\nG\nC" | java Test

Where am I wrong ? Thanks.


Solution

  • Your simply need to flush and close os stream in method run() of the Grep class after the block of code:

    while((c=this.pipeInPipedInputStream.read())!=-1)
    {   
        os.write((char)c);
    }
    

    add this lines:

    os.flush();
    os.close();
    

    And your method run() of the Grep class must look like:

    @Override
    public void run()
    {
        try {
            Process proc=Runtime.getRuntime().exec(new String[]{
                 "/bin/grep",
                 "A"});
            OutputStream os=proc.getOutputStream();
    
            Thread t1=new Thread(new CopyTo(proc.getErrorStream(),System.err));
            Thread t2=new Thread(new CopyTo(proc.getInputStream(),System.out));
            t1.start();
            t2.start();
            int c;
            while((c=this.pipeInPipedInputStream.read())!=-1)
            {   
                 os.write((char)c);
            }
    
            //missing lines of code
            os.flush();
            os.close();
    
            t1.join();
            t2.join();
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    The output of the command:

    $ javac Test.java && echo -e "A\nT\nG\nC" | java Test
    

    will be:

    A
    

    and program will terminated.