How can I pipe input to a Java app with Perl?
I need to write a Perl script that pipes input into a Java program. This is related to this, but that didn't help me. My issue is that the Java app doesn't get the print statements until I close the handle. What I found online was that $| needs to be set to something g开发者_JAVA技巧reater than 0, in which case newline characters will flush the buffer. This still doesn't work.
This is the script:
#! /usr/bin/perl -w
use strict;
use File::Basename;
$|=1;
open(TP, "| java -jar test.jar") or die "fail";
sleep(2);
print TP "this is test 1\n";
print TP "this is test 2\n";
print "tests printed, waiting 5s\n";
sleep(5);
print "wait over. closing handle...\n";
close TP;
print "closed.\n";
print "sleeping for 5s...\n";
sleep(5);
print "script finished!\n";
exit
And here is a sample Java app:
import java.util.Scanner;
public class test{
public static void main( String[] args ){
Scanner sc = new Scanner( System.in );
int crashcount = 0;
while( true ){
try{
String input = sc.nextLine();
System.out.println( ":: INPUT: " + input );
if( "bananas".equals(input) ){
break;
}
} catch( Exception e ){
System.out.println( ":: EXCEPTION: " + e.toString() );
crashcount++;
if( crashcount == 5 ){
System.out.println( ":: Looks like stdin is broke" );
break;
}
}
}
System.out.println( ":: IT'S OVER!" );
return;
}
}
The Java app should respond to receiving the test prints immediately, but it doesn't until the close statement in the Perl script. What am I doing wrong?
Note: the fix can only be in the Perl script. The Java app can't be changed. Also, File::Basename is there because I'm using it in the real script.
I've grown rather fond of the IO::Handle
derived modules. They make it easy to control flushing, reading data, binary mode, and many other aspects of a handle.
In this case we use IO::File.
use IO::File;
my $tp = IO::File->new( "| java -jar test.jar" )
or die "fail - $!";
# Manual print and flush
$tp->print( 'I am fond of cake' );
$tp->flush;
# print and flush in one method
$tp->printflush( 'I like pie' );
# Set autoflush ON
$tp->autoflush(1);
$tp->print( 'I still like pie' );
Also, since the file handle is lexically scoped, you don't have to close it manually. It will automatically close when it goes out of scope.
BTW, unless you are targeting a perl
older than 5.6, you can use the warnings
pragma instead of -w
. See perllexwarn for more info.
$|=1 only works on the currently selected file handle (by default, STDOUT). To make your TP file handle hot you need to do this after opening it:
select(TP);
$| = 1;
select(STDOUT);
精彩评论