Rushdi Shams
Rushdi Shams

Reputation: 2423

To check if a file is written completely

How do I know if a software is done writing a file if I am executing that software from java?For example, I am executing geniatagger.exe with an input file RawText that will produce an output file TAGGEDTEXT.txt. When geniatagger.exe is finished writing the TAGGEDTEXT.txt file, I can do some other staffs with this file. The problem is- how can I know that geniatagger is finished writing the text file?

try{
  Runtime rt = Runtime.getRuntime();
    Process p = rt.exec("geniatagger.exe -i "+ RawText+ " -o TAGGEDTEXT.txt");
  }

Upvotes: 1

Views: 3887

Answers (2)

JBert
JBert

Reputation: 3390

You can't, or at least not reliably.

In this particular case your best bet is to watch the Process complete.

You get the process' return code as a bonus, this could tell you if an error occurred.

If you are actually talking about this GENIA tagger, below is a practical example which demonstrates various topics (see explanation about numbered comments beneath the code). The code was tested with v1.0 for Linux and demonstrates how to safely run a process which expects both input and output stream piping to work correctly.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.concurrent.Callable;

import org.apache.commons.io.IOUtils;

public class GeniaTagger {

    /**
     * @param args
     */
    public static void main(String[] args) {
        tagFile(new File("inputText.txt"), new File("outputText.txt"));
    }

    public static void tagFile(File input, File output) {
        FileInputStream ifs = null;
        FileOutputStream ofs = null;
        try {
            ifs = new FileInputStream(input);
            ofs = new FileOutputStream(output);
            final FileInputStream ifsRef = ifs;
            final FileOutputStream ofsRef = ofs;

            // {1}    
            ProcessBuilder pb = new ProcessBuilder("geniatagger.exe");
            final Process pr = pb.start();

            // {2}
            runInThread(new Callable<Void>() {
                public Void call() throws Exception {
                    IOUtils.copy(ifsRef, pr.getOutputStream());
                    IOUtils.closeQuietly(pr.getOutputStream());   // {3}
                    return null;
                }
            });
            runInThread(new Callable<Void>() {
                public Void call() throws Exception {
                    IOUtils.copy(pr.getInputStream(), ofsRef);   // {4}
                    return null;
                }
            });
            runInThread(new Callable<Void>() {
                public Void call() throws Exception {
                    IOUtils.copy(pr.getErrorStream(), System.err);
                    return null;
                }
            });

            // {5}
            pr.waitFor();
            // output file is written at this point.
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // {6}
            IOUtils.closeQuietly(ifs);
            IOUtils.closeQuietly(ofs);
        }
    }

    public static void runInThread(final Callable<?> c) {
        new Thread() {
            public void run() {
                try {
                    c.call();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                }
            }
        }.start();
    }
}
  1. Use a ProcessBuilder to start your process, it has a better interface than plain-old Runtime.getRuntime().exec(...).

  2. Set up stream piping in different threads, otherwhise the waitFor() call in ({5}) might never complete.

  3. Note that I piped a FileInputStream to the process. According to the afore-mentioned GENIA page, this command expects actual input instead of a -i parameter. The OutputStream which connects to the process must be closed, otherwhise the program will keep running!

  4. Copy the result of the process to a FileOutputStream, the result file your are waiting for.

  5. Let the main thread wait until the process completes.

  6. Clean up all streams.

Upvotes: 1

maerics
maerics

Reputation: 156434

If the program exits after generating the output file then you can call Process.waitFor() to let it run to completion then you can process the file. Note that you will likely have to drain both the standard output and error streams (at least on Windows) for the process to finish.

[Edit]

Here is an example, untested and likely fraught with problems:

  // ...
  Process p = rt.exec("geniatagger.exe -i "+ RawText+ " -o TAGGEDTEXT.txt");
  drain(p.getInputStream());
  drain(p.getErrorStream());
  int exitCode = p.waitFor();
  // Now you should be able to process the output file.
}

private static void drain(InputStream in) throws IOException {
  while (in.read() != -1);
}

Upvotes: 0

Related Questions