Pipe data from InputStream to OutputStream in Java - java

I'd like to send a file contained in a ZIP archive unzipped to an external program for further decoding and to read the result back into Java.
ZipInputStream zis = new ZipInputStream(new FileInputStream(ZIPPATH));
Process decoder = new ProcessBuilder(DECODER).start();
???
BufferedReader br = new BufferedReader(new InputStreamReader(
decoder.getInputStream(),"us-ascii"));
for (String line = br.readLine(); line!=null; line = br.readLine()) {
...
}
What do I need to put into ??? to pipe the zis content to the decoder.getOutputStream()? I guess a dedicated thread is needed, as the decoder process might block when its output is not consumed.

Yes a thread is needed (or you wait/block until the copy is finished) for copying the InputStream to the OutputStream. Check the org.apache.commons.net.io.Util class for several helper methods to copy the data.

Ok, I got as far as following:
public class CopyStream extends Thread {
static final int BUFFERSIZE = 10 * 1024;
InputStream input; OutputStream output;
boolean closeInputOnExit, closeOutputOnExit, flushOutputOnWrite;
public IOException ex;
public CopyStream (InputStream input, boolean closeInputOnExit, OutputStream output, boolean closeOutputOnExit,
boolean flushOutputOnWrite) {
super("CopyStream");
this.input = input; this.closeInputOnExit = closeInputOnExit;
this.output = output; this.closeOutputOnExit = closeOutputOnExit;
this.flushOutputOnWrite = flushOutputOnWrite;
start();
}
public void run () {
try {
byte[] buffer = new byte[BUFFERSIZE];
for (int bytes = input.read(buffer); bytes>=0; bytes = input.read(buffer)) {
output.write(buffer,0,bytes);
if (flushOutputOnWrite) output.flush();
}
} catch (IOException ex) {
this.ex = ex;
} finally {
if (closeInputOnExit) {
try {
input.close();
} catch (IOException ex) {
if (this.ex==null) this.ex = ex;
}
}
if (closeOutputOnExit) {
try {
output.close();
} catch (IOException ex) {
if (this.ex==null) this.ex = ex;
}
}
}
}
}
Then the code would look as following:
ZipInputStream zis = new ZipInputStream(new FileInputStream(ZIPPATH));
for (ZipEntry ze = zis.getNextEntry(); ze!=null; ze = zis.getNextEntry()) {
Process decoder = new ProcessBuilder(EXTERNALPROCESSOR).start();
CopyStream cs1 = new CopyStream(is,false,decoder.getOutputStream(),true,true);
CopyStream cs2 = new CopyStream(decoder.getErrorStream(),true,System.err,false,true);
BufferedReader br = new BufferedReader(new InputStreamReader(decoder.getInputStream(),"us-ascii"));
ArrayList<String> lines = new ArrayList<String>();
for (String line = br.readLine(); line!=null; line = br.readLine()) {
lines.add(line);
}
if (decoder.exitValue()!=0) throw new IOException("Decoder exits with "+decoder.exitValue());
try {
cs1.join(100);
} catch (InterruptedException ex) {
throw new IOException(ex);
}
if (cs1.isAlive()) throw new IOException("cs1 not terminated");
if (cs1.ex!=null) throw cs1.ex;
try {
cs2.join(100);
} catch (InterruptedException ex) {
throw new IOException(ex);
}
if (cs2.isAlive()) throw new IOException("cs2 not terminated");
if (cs2.ex!=null) throw cs2.ex;
for (String line: lines) {
processline(line);
}
}
However, I find this a bit fragile. Isn't this a pattern for which some more robust implementation is around?

Related

Why is this not reading in?

I know I'm not doing something correctly. I know the file needs to be Serializable to read a text file.
I've got implements Serializable on the main class. But my readText and my writeText aren't converting.
Nothing is coming in when I read and when I write out the file is not text.
public static ArrayList<String> readText() {
ArrayList<String> read = new ArrayList<String>();
Frame f = new Frame();
FileDialog foBox = new FileDialog(f, "Reading serialized file",
FileDialog.LOAD);
foBox.setVisible(true);
String foName = foBox.getFile();
String dirPath = foBox.getDirectory();
File inFile = new File(dirPath + foName);
BufferedReader in = null;
ObjectInputStream OIS = null;
try {
in = new BufferedReader(new FileReader(inFile));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
String line = null;
try {
line = in.readLine();
} catch (IOException e1) {
e1.printStackTrace();
while (line != null) {
try {
FileInputStream IS = new FileInputStream(inFile);
OIS = new ObjectInputStream(IS);
inFile = (File) OIS.readObject();
} catch (IOException io) {
io.printStackTrace();
System.out.println("An IO Exception occurred");
}
catch (ClassNotFoundException cnf) {
cnf.printStackTrace(); // great for debugging!
System.out.println("An IO Exception occurred");
} finally
{
try {
OIS.close();
} catch (Exception e) {
}
}
}
}
return read;
}
public static void writeText(ArrayList<String> file) {
ArrayList<String> write = new ArrayList<String>();
Frame f = new Frame();
FileDialog foBox = new FileDialog(f, "Saving customer file",
FileDialog.SAVE);
foBox.setVisible(true);
String foName = foBox.getFile();
String dirPath = foBox.getDirectory();
File outFile = new File(dirPath + foName);
PrintWriter out = null;
try {
out = new PrintWriter(new BufferedWriter(new FileWriter(outFile)));
for (int i = 0; i < write.size(); i++) {
String w = write.get(i);
out.println(file.toString());
}
}
catch (IOException io) {
System.out.println("An IO Exception occurred");
io.printStackTrace();
} finally {
try {
out.close();
} catch (Exception e) {
}
}
}
Nothing is coming in
You're never calling read.add(line) and you're attempting to read the file within an infinite loop inside of the catch block, which is only entered if you are not able to read the file.
Just use one try block, meaning try to open and read the file at once, otherwise, there's no reason to continue trying to read the file if it's not able to be opened
List<String> read = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(inFile)) {
String line = null;
while ((line = in.readLine()) != null) {
read.add(line); // need this
}
} catch (Exception e) {
e.printStackTrace();
}
return read;
Now, whatever you're doing with this serialized object stuff, that's completely separate, and it isn't the file or your main class that needs set to Serializable, it's whatever object you would have used a writeObject method on. However, you're reading and writing String objects, which are already Serializable.
when I write out the file is not text
Not sure what you mean by not text, but if you followed the above code, you'll get exactly what was in the initial file... Anyway, you do not need a write list variable.
You must use the individual lines of ArrayList<String> file parameter instead, but not file.toString()
for (String line:file) {
out.println(line);
}
out.close(); // always close your files and writers

How to read a file with Java's BufferedReader vs InputStreamReader?

Below I have the following code to read in a file and go through it line by line.. This is using java's BufferedReader class. That I am fine with.
String filename = "C:\\test.txt"
String line = null;
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
try {
while (((line = bufferedReader.readLine()) != null)) {
//do the following....
}
} catch (IOException) {
e.printStackTrace();
}
However I want to now start using InputStreamReader in Spring / Java. I have the below code written but I am unsure how I can step through my file line by line. Really confused over this part. Anyone have any ideas or know how this can be done?
String filepath= "C:\\test.txt"
File filename= new File(filepath);
try {
InputStream fileInputStream = new BOMInputStream(new fileInputStream(filename));
// now want to step through the file, line by line..
} catch (IOException) {
e.printStackTrace();
}
Thanks
This is how you can read your input file byte by byte using InputStreamReader.
char[] chars = new char[100];
try {
InputStream inputStream = new FileInputStream("C:\\test.txt");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");
inputStreamReader.read(chars);
System.out.println(new String(chars).trim());
} catch (IOException e) {
e.printStackTrace();
}
Check this out -
String filename = "C:\\test.txt"
String line = null;
FileInputStream fileInputStream = new FileInputStream(filename);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
try {
while (((line = bufferedReader.readLine()) != null)) {
//do the following....
}
} catch (IOException) {
e.printStackTrace();
}
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("c:\\test.txt")))) {
reader.lines().forEach(line -> {
// do what you want with the line
});
} catch (IOException e) {
throw new RuntimeException(e);
}
}

Java Wget Bz2 file

I'm trying to webget some bz2 files from Wikipedia, I don't care whether they are save as bz2 or unpacked, since I can unzip them locally.
When I call:
public static void getZip(String theUrl, String filename) throws IOException {
URL gotoUrl = new URL(theUrl);
try (InputStreamReader isr = new InputStreamReader(new BZip2CompressorInputStream(gotoUrl.openStream())); BufferedReader in = new BufferedReader(isr)) {
StringBuffer sb = new StringBuffer();
String inputLine;
// grab the contents at the URL
while ((inputLine = in.readLine()) != null) {
sb.append(inputLine + "\r\n");
}
// write it locally
Wget.createAFile(filename, sb.toString());
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
throw ioe;
}
}
I get a part of the unzipped file, never more than +- 883K.
When I don't use the BZip2CompressorInputStream, like:
public static void get(String theUrl, String filename) throws IOException {
try {
URL gotoUrl = new URL(theUrl);
InputStreamReader isr = new InputStreamReader(gotoUrl.openStream());
BufferedReader in = new BufferedReader(isr);
StringBuffer sb = new StringBuffer();
String inputLine;
// grab the contents at the URL
while ((inputLine = in.readLine()) != null) {
sb.append(inputLine);// + "\r\n");
}
// write it locally
Statics.writeOut(filename, false, sb.toString());
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
throw ioe;
}
}
I get a file of which the size is the same as it suppose to (compared to the KB not B). But also a message that that the zipped file is damaged, also when using byte [] instead of readLine(), like:
public static void getBytes(String theUrl, String filename) throws IOException {
try {
char [] cc = new char[1024];
URL gotoUrl = new URL(theUrl);
InputStreamReader isr = new InputStreamReader(gotoUrl.openStream());
BufferedReader in = new BufferedReader(isr);
StringBuffer sb = new StringBuffer();
// grab the contents at the URL
int n = 0;
while (-1 != (n = in.read(cc))) {
sb.append(cc);// + "\r\n");
}
// write it locally
Statics.writeOut(filename, false, sb.toString());
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
throw ioe;
}
}
Finally, when I bzip2 the inputstream and outputstream, I get a valid bzip2 file, but of the size like the first one, using:
public static void getWriteForBZ2File(String urlIn, final String filename) throws CompressorException, IOException {
URL gotoUrl = new URL(urlIn);
try (final FileOutputStream out = new FileOutputStream(filename);
final BZip2CompressorOutputStream dataOutputStream = new BZip2CompressorOutputStream(out);
final BufferedInputStream bis = new BufferedInputStream(gotoUrl.openStream());
final CompressorInputStream input = new CompressorStreamFactory().createCompressorInputStream(bis);
final BufferedReader br2 = new BufferedReader(new InputStreamReader(input))) {
String line = null;
while ((line = br2.readLine()) != null) {
dataOutputStream.write(line.getBytes());
}
}
}
So, how do I get the entire bz2 file, in either bz2 format or unzipped?
A bz2 file contains bytes, not characters. You can't read it as if it contained characters, with a Reader.
Since all you want to do is download the file and save it locally, all you need is
Files.copy(gotoUrl.openStream(), Paths.get(fileName));

How can I run executable in assets?

How can I add a executable into assets and run it in Android and show the output?
I've a executable that will work. I assume there will need to be some chmod in the code.
Thank you.
here is my answer
put copyAssets() to your mainactivity.
someone's code:
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
for(String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
File outFile = new File(getFilesDir(), filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// NOOP
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
// NOOP
}
}
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
also here is code to run command
public String runcmd(String cmd){
try {
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer out = new StringBuffer();
while ((read = in.read(buffer)) > 0) {
out.append(buffer, 0, read);
}
in.close();
p.waitFor();
return out.substring(0);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
you may need to change it to
String prog= "programname";
String[] env= { "parameter 1","p2"};
File dir= new File(getFilesDir().getAbsolutePath());
Process p = Runtime.getRuntime().exec(prog,env,dir);
to ensure proper parameter handling
also add this to your main code
to check proper copying of files
String s;
File file4 = new File(getFilesDir().getAbsolutePath()+"/executable");
file4.setExecutable(true);
s+=file4.getName();
s+=file4.exists();
s+=file4.canExecute();
s+=file4.length();
//output s however you want it
should write: filename, true, true, correct filelength.
Place your executable in raw folder, then run it by using ProcessBuilder or Runtime.exec like they do here http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

android get stderr of command

How can i get the stderr of a python binary? It is showing the output of the python script but it is not showing the errors that might be in the script, what java method should i be using? or is there a python command line argument that i can use to display the errors?
private String exec(String command)
{
try
{
String s = getApplicationInfo().dataDir;
File file2 = new File(s+"/py");
file2.setExecutable(true);
File externalStorage = Environment.getExternalStorageDirectory();
String strUri = externalStorage.getAbsolutePath();
PrintWriter out = new PrintWriter(strUri+"/temp.py");
out.write(command);
out.close();
saveRawToFile();
Process process = Runtime.getRuntime().exec(s+"/py "+strUri+"/temp.py");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0)
{
output.append(buffer, 0, read);
}
reader.close(); process.waitFor();
return output.toString();
}
catch (IOException e)
{ throw new RuntimeException(e); }
catch (InterruptedException e)
{ throw new RuntimeException(e); }
}
private void output(final String str)
{
Runnable proc = new Runnable() {
public void run()
{
outputView.setText(str);
outputView.setTextIsSelectable(true);
}
};
handler.post(proc);
}
Use Process#getErrorStream(), just like you used getOutputStream().

Categories

Resources