PrintWriter erases file of contents before the close() function executed - java

I am trying to write contents of my parsed HTML with PrintWriter so I can convert HTML to the other formats. But PrintWriter erases file of contents before the close() function executedçI can use other file writing techniques but I am wondering why PrintWriter behave like this.
for (Element element : elements) {
if (element.tagName() == "a") {
PrintWriter writer2 = new PrintWriter("contenthtml.html", "UTF-8");
writer2.print(a.ExtractHTMLByIDandDomain(Domain + element.attr("href"), Content_HTML_ID));
Process proc = Runtime.getRuntime().exec("pandoc -f html -t asciidoc contenthtml.html >> contentasciidoc.adoc");
//Thread.sleep(5000); //I have tried wait but it didn't work
writer2.flush();
writer2.close();
}

There are a few problems with your code:
You cannot compare strings with '==', as '==' compares references. If element.getTagName() is "a", whether that if on line 2 of your paste actually fires depends on the situation, but it probably wont.
A PrintWriter is a resource. Resources need to be closed; if you do not close them, the resource remains open indefinitely, and this is called a resource leak. Use the Automatic Resource Management construct for a convenient way to do so.
You create the printwriter, tell the printwriter to write some data, you do not flush or close the resource, you then exec another process, and finally after that process completes, you flush/close. Which means, the file is empty, as printwriter buffers. You should write your file and then close your resource, and only then call the external process; both you and the process you launch having the same file open at the same time is confusing and problematic, and in this case, unneccessary, so, don't.
Runtime.getRuntime().exec() is NOT bash and NOT a command line prompt. The concept of redirecting via >> someFile.txt is a bashism/command-promptism. Runtime has no idea what you're talking about and will just pass it along as an argument to the launched process. Invoke bash if you need bash's redirection features or write the redirection in java by reading the outputstream of the process and appending it to the file yourself.
Applying all 4 fixes:
create a file named 'run.sh' containing:
#!/bin/sh
pandoc -f html -t asciidoc contenthtml.html >> contentasciidoc.asciidoc
and update your java code:
for (Element element : elements) {
if ("a".equalsIgnoreCase(element.tagName()) {
try (PrintWriter writer2 = new PrintWriter("contenthtml.html", "UTF-8")) {
writer2.print(a.ExtractHTMLByIDandDomain(Domain + element.attr("href"), Content_HTML_ID));
}
}
Process proc = Runtime.getRuntime().exec("/usr/bin/bash run.sh");
}

There is no guarantee that PrintWriter will write to the file until you call flush()
It might work if you move flush() to before exec()

First: Please read an try to understand the answer rzwitserloot wrote because it contains some valid constructive criticism.
To answer your question why PrintWriter deletes already existing file contents: It's designed to do so. If you look in the documentation for PrintWriter which you can find here: https://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#PrintWriter(java.io.File,%20java.lang.String)
The part about the File Parameter:
file - The file to use as the destination of this writer.
If the file exists then it will be truncated to zero size; otherwise, a new file will be created. The output will be written to the file and is buffered.

Related

Start another jar and provide input to it

I need to start jar and provide input to it.
I've found how to start jar, which works without problems, using Runtime#getRuntime#exec, and I've also found that
String command = "stop";
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bufferedWriter.write(String.format("%s\n", command));
bufferedWriter.flush();
should do the job. But the problem is, it just doesn't work for me, it literally does nothing. Does anyone know how to do that?
Process:
public static Process startJar(File jarFile, String flags, String args, #Nullable File dir) throws IOException {
if (dir == null){
return Runtime.getRuntime().exec(String.format("cmd /c start /wait \"\" java -jar %s \"%s\" %s",flags ,jarFile.getAbsolutePath(), args));
}
return Runtime.getRuntime().exec(String.format("cmd /c start /wait \"\" java -jar %s \"%s\" %s", flags, jarFile.getAbsolutePath(), args), null, dir);
}
If the input is commandline args, pass it to exec directly.
If not, and assuming process is the other jar you are running, you'll need to write to the InputStream of process, not the OutputStream. process.getOutputStream() will give you the stream to which the process is outputting its results, not where it's reading its input from.
EDIT: After Taschi pointed out that the code is correct
I found another question similar to yours. The accepted answer states that you have to either close the writer or pass a \n in order for it to work. Try that. If it still doesn't work, make sure the other JAR you're running is actually waiting for input on its STDIN.
I assume your process is blocked because it tried to write something to its output, and you did not read it. The API doc states:
Because some native platforms only provide limited buffer size for
standard input and output streams, failure to promptly write the input
stream or read the output stream of the subprocess may cause the
subprocess to block, or even deadlock.
So, read from process.getInputStream() and process.getErrorStream() unless both of them are empty, and then it should process your input just fine.
See here: Starting a process in Java? for a possible example on how to read.
The problem was, that I was starting that jar in a new window (cmd /c start), after removing that, everything works without a problem.

NoSuchFileException in Files.newInputStream with StandardOpenOption.CREATE

I am trying to open a file for reading or create the file if it was not there.
I use this code:
String location = "/test1/test2/test3/";
new File(location).mkdirs();
location += "fileName.properties";
Path confDir = Paths.get(location);
InputStream in = Files.newInputStream(confDir, StandardOpenOption.CREATE);
in.close();
And I get java.nio.file.NoSuchFileException
Considering that I am using StandardOpenOption.CREATE option, the file should be created if it is not there.
Any idea why I am getting this exception?
It seems that you want one of two quite separate things to happen:
If the file exists, read it; or
If the file does not exist, create it.
The two things are mutually exclusive but you seem to have confusingly merged them. If the file did not exist and you've just created it, there's no point in reading it. So keep the two things separate:
Path confDir = Paths.get("/test1/test2/test3");
Files.createDirectories(confDir);
Path confFile = confDir.resolve("filename.properties");
if (Files.exists(confFile))
try (InputStream in = Files.newInputStream(confFile)) {
// Use the InputStream...
}
else
Files.createFile(confFile);
Notice also that it's better to use "try-with-resources" instead of manually closing the InputStream.
Accordingly to the JavaDocs you should have used newOutputStream() method instead, and then you will create the file:
OutputStream out = Files.newOutputStream(confDir, StandardOpenOption.CREATE);
out.close();
JavaDocs:
// Opens a file, returning an input stream to read from the file.
static InputStream newInputStream(Path path, OpenOption... options)
// Opens or creates a file, returning an output stream that
// may be used to write bytes to the file.
static OutputStream newOutputStream(Path path, OpenOption... options)
The explanation is that OpenOption constants usage relies on wether you are going to use it within a write(output) stream or a read(input) stream. This explains why OpenOption.CREATE only works deliberatery with the OutputStream but not with InputStream.
NOTE: I agree with #EJP, you should take a look to Oracle's tutorials to create files properly.
I think you intended to create an OutputStream (for writing to) instead of an InputStream (which is for reading)
Another handy way of creating an empty file is using apache-commons FileUtils like this
FileUtils.touch(new File("/test1/test2/test3/fileName.properties"));

Clear contents of a file in Java using RandomAccessFile

I am trying to clear the contents of a file I made in java. The file is created by a PrintWriter call. I read here that one can use RandomAccessFile to do so, and read somewhere else that this is in fact better to use than calling a new PrintWriter and immediately closing it to overwrite the file with a blank one.
However, using the RandomAccessFile is not working, and I don't understand why. Here is the basic outline of my code.
PrintWriter writer = new PrintWriter("temp","UTF-8");
while (condition) {
writer.println("Example text");
if (clearCondition) {
new RandomAccessFile("temp","rw").setLength(0);
// Although the solution in the link above did not include ',"rw"'
// My compiler would not accept without a second parameter
writer.println("Text to be written onto the first line of temp file");
}
}
writer.close();
Running the equivalent of the above code is giving my temp file the contents:(Lets imagine that the program looped twice before clearCondition was met)
Example Text
Example Text
Text to be written onto the first line of temp file
NOTE: writer needs to be able to write "Example Text" to the file again after the file is cleared. The clearCondition does not mean that the while loop gets broken.
You want to either flush the PrintWriter to make sure the changes in its buffer are written out first, before you set the RandomAccessFile's length to 0, or close it and re-open a new PrintWriter to write the last line (Text to be written...). Preferably the former:
if (clearCondition) {
writer.flush();
new RandomAccessFile("temp","rw").setLength(0);
You'll be lucky if opening the file twice at the same time works. It isn't specified to work by Java.
What you should do is close the PrintWriter and open a new one without the 'append' parameter, or with 'append' set to 'false'.

FileDescriptor of Directory in Java

is there a way to open a directory stream in Java like in C? I need a FileDescriptor of an opened directory. Well, actually just the number of the fd.
I try to implement a checkpoint/restore functionality in Java with the help of CRIU link. To do this, I need to deploy a RPC call to the CRIU service. There I have to provide the integer value of the FD of an already opened directory, where the image files of the process will be stored.
Thank you in advance!
is there a way to open a directory stream in Java like in C?
No there isn't. Not without resorting to native code.
If you want to "read" a directory in (pure) Java, you can do it using one of the following:
File.list() - gives you the names of the directory entries as strings.
File.list(FilenameFilter) - ditto, but only directory entries that match are returned.
File.listFiles() - like list() but returning File objects.
etcetera
Files.newDirectoryStream(Path) gives you an iterator for the Path objects for the entries in a directory.
The last one could be "close" to what you are trying to achieve, but it does not entail application code getting hold of a file descriptor for a directory, or the application doing a low-level "read" on the directory.
You don't need FD in Java. All you need is a reference to that file which you can simply acquire using File file = new File("PathToYourFile");
To read/write you have Streams in Java. You can use
BufferedReader fileReader = new BufferedReader(new FileReader(new File("myFile.txt")));
PrintWriter fileWriter = new PrintWriter(new FileWriter(new File("myFile.txt")));
Even directory is a file. You can use isDirectory() on file object to check if it is a directory or a file.
private FileDescriptor openFile(String path)
throws FileNotFoundException, IOException {
File file = new File(path);
FileOutputStream fos = new FileOutputStream(file);
// remember th 'fos' reference somewhere for later closing it
fos.write((new Date() + " Beginning of process...").getBytes());
return fos.getFD();
}

Write to External File without ending the program

I have a program that is only meant to be terminated by pressing Ctrl + C. In this program I write to an external file using:
File logFile = new File("output.txt");
PrintWriter log_file_writer = new PrintWriter(logFile);
log_file_writer.println("TEXT");
However because I don't know when the program will be terminated, I can't close the file using:
log_file_writer.close();
I think this is resulting in no text appearing in the output file.
Would anyone have a solution for this?
Thank you for your help.
log_file_writer.flush();
will push the content to disk
As the javadoc says:
PrintWriter(File file) Creates a new PrintWriter, without automatic line flushing, with the specified file.
Therefore, you need to flush the data you want to print that is actually buffered:
log_file_writer.flush();
You did not flush the content, I always use the autoFlush argument, but it is not available with File:
PrintWriter log_file_writer = new PrintWriter(new FileOutputStream("output.txt"),true);
but you can also use log_file_writer.flush(); after each write.

Categories

Resources