Make PrintWriter or OutputStreamWriter print immediately - java

Is there a way to make PrintWriter or OutputStreamWriter print immediately after .write method is invoked? I have autoFlush turned on for PrintWriter. Yet for both these classes, the contents get printed only when the writer is closed.
For what it's worth, I am using Writers because I need to abstract over console output, file output, and string output.
Thanks!
Edit:
An SSCCE that shows the problem:
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
PrintWriter p = new PrintWriter(System.out, true);
Scanner read = new Scanner(System.in);
while (read.hasNextLine()) {
String input = read.nextLine();
if (input.equals("end"))
break;
p.write(input);
}
p.close();
}
}
/* Sample run: (first four lines are input)
cow
mow
pow
end
cowmowpow
*/

The documentation for the autoFlush constructor parameter says:
A boolean; if true, the println, printf, or format methods will flush the output buffer
Given that you're not using any of those methods, it's not entirely surprising that it's not helping.
The simplest approach would be to just call flush() manually after every write - that's what you're trying to achieve, after all. I don't know of anything which will make a writer flush by default after every write.
Of course, you could write your own wrapper class - the equivalent of BufferedWriter, but with the opposite effect. It could delegate all methods to the wrapped writer, but then immediately call flush() afterwards.

Related

Storing String input in a file

Ok, before anyone starts flaming me for asking "dumb" questions, please note that I have pretty much exhausted every other option that I know of and come up empty handed. Still if you feel like it, please go ahead and downvote/report this question.
Now, for those that care
I am trying to take a String input from user and store it into a file Text.txt which will be created in the current working directory.
Following is the code
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Scanner;
public class Encryption {
public static void main(String[] args) throws Exception {
System.out.println("Enter a String you wish to encrypt : ");
new BufferedWriter(new FileWriter(".\\Text.txt")).write(new Scanner(System.in).nextLine());
System.out.println("Done");
}
}
My problem is, the file is getting generated at the correct destination, but is always empty. I have tried it on multiple JDK versions and on different machines. Still getting the blank text file.
Please tell me, what is it that I am doing wrong.
You are not closing with .close() the BufferedWriter (which would then flush the last buffer and close the file).
You can however do that task in new style:
Files.write(Paths.get(".\\Text.txt"),
Arrays.asList(new Scanner(System.in).nextLine()),
Charset.defaultCharset());
Otherwise you would need to introduce a variable, and gone is the one-liner.
Some changes i made your code to work
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Scanner;
public class Encryption {
public static void main(String[] args) throws Exception {
System.out.println("Enter a String you wish to encrypt : ");
String text = new Scanner(System.in).nextLine();
BufferedWriter b = new BufferedWriter(new FileWriter(".\\Text.txt"));
b.write(text);
b.close();
System.out.println("Done");
}
}

Assert an InputStream and an Output stream are equal

Is there any simple way to test (in Junit) if the content of an input stream is equal to the content of an output one?
Not only there is no simple way to test this, there is no way to make this comparison in general case.
An output stream is an abstraction that allows write-only implementations for transmit-and-forget streams. There is no general way to get back what has been written
An input stream may not allow rewinding. This is less of a problem, because you may be OK with "destructive" reads, but one needs to be careful in that area as well.
You need to make your own wrapper around the output stream, pass it to the program being tested, and then harvest what has been written into it. After that you can read your input stream, and compare its content with what has been captured.
ByteArrayOutputStream may help you capture the output of the code that you test. Commons IO provide two classes that may be helpful - TeeInputStream and TeeOutputStream.
There is no built in way, but you might still be able to test it. It depends what you are doing. Here is a simple case...
Say if I had this method...
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.springframework.util.StreamUtils;
public class Stack {
public static void copy(InputStream in, OutputStream out) {
try {
StreamUtils.copy(in, out);
} catch(IOException io) {
throw new RuntimeException("BOOM!");
}
}
}
I could test this method like this...
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import org.junit.Test;
public class StackTest {
#Test
public void shouldCopyFromInputToOutput() {
byte[] contents = new byte[] { 1, 2, 3 };
ByteArrayOutputStream out = new ByteArrayOutputStream();
Stack.copy(new ByteArrayInputStream(contents), out);
byte[] written = out.toByteArray();
assert Arrays.equals(contents, written);
}
}
So I am not testing if the output and input streams are "equal", but instead I am making assertions on what the method actually does.
Hope this helps.

FileWriter object reference not being overwritten as expected

I was working with a fellow peer on a simple coding exercise and we stumbled across this issue.
The program requirements outlined that if the third command line argument was "a", the output file should be appended to, not replaced.
So, he had code something like this:
import java.io.FileWriter;
import java.io.IOException;
public class MyFileWriter {
public static void main(String[] args) {
//...
try {
FileWriter fw = new FileWriter("testfile");
if(args[2].equals("a")) {
fw = new FileWriter("testfile", true);
}
else if(args[2].equals("r")) {
fw = new FileWriter("testfile");
}
}
catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
I know that initializing FileWriter before either of the if statements is redundant, but that's how it was set up. We ran it with the third command line argument being "a", and that if statement ran successfully. However, the FileWriter object was not appending to the file as was expected.
We changed the initial declaration of the FileWriter to the following:
FileWriter fw = null;
And then it worked. I figured it had to be some kind of reference or pointer issue, but why? Theoretically, the assignment operator should overwrite the value of whatever the thing points to, so even though initializing it to begin with is redundant, it should just overwrite the object entirely.
Anyone know why this was an issue? I'm just curious.
I figured it had to be some kind of reference or pointer issue, but why?
No, its a matter of your code flow and how you call the FileWriter() constructor.
The first call to FileWriter() in
try {
FileWriter fw = new FileWriter("testfile");
....
already overwrites and clears the file, before you later on create another FileWriter which was intended to append to it:
...
if(args[2].equals("a")) {
fw = new FileWriter("testfile", true); // here, "testfile" was already overwritten
}
...
Hence, effectively you are appending to an empty file.
Keep in mind that Constructors can contain any kind of program code. You do not even necessarily have to assign the "result" of the constructor call to a variable - the following would have the same effect of overwriting the file:
...
new FileWriter("testfile");
....

Java8:Handling a checked exception in java8 lambda's like Stream.forEach() Method [duplicate]

I'd like to read in a file and replace some text with new text. It would be simple using asm and int 21h but I want to use the new java 8 streams.
Files.write(outf.toPath(),
(Iterable<String>)Files.lines(inf)::iterator,
CREATE, WRITE, TRUNCATE_EXISTING);
Somewhere in there I'd like a lines.replace("/*replace me*/","new Code()\n");. The new lines are because I want to test inserting a block of code somewhere.
Here's a play example, that doesn't work how I want it to, but compiles. I just need a way to intercept the lines from the iterator, and replace certain phrases with code blocks.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static java.nio.file.StandardOpenOption.*;
import java.util.Arrays;
import java.util.stream.Stream;
public class FileStreamTest {
public static void main(String[] args) {
String[] ss = new String[]{"hi","pls","help","me"};
Stream<String> stream = Arrays.stream(ss);
try {
Files.write(Paths.get("tmp.txt"),
(Iterable<String>)stream::iterator,
CREATE, WRITE, TRUNCATE_EXISTING);
} catch (IOException ex) {}
//// I'd like to hook this next part into Files.write part./////
//reset stream
stream = Arrays.stream(ss);
Iterable<String> it = stream::iterator;
//I'd like to replace some text before writing to the file
for (String s : it){
System.out.println(s.replace("me", "my\nreal\nname"));
}
}
}
edit: I've gotten this far and it works. I was trying with filter and maybe it isn't really necessary.
Files.write(Paths.get("tmp.txt"),
(Iterable<String>)(stream.map((s) -> {
return s.replace("me", "my\nreal\nname");
}))::iterator,
CREATE, WRITE, TRUNCATE_EXISTING);
The Files.write(..., Iterable, ...) method seems tempting here, but converting the Stream to an Iterable makes this cumbersome. It also "pulls" from the Iterable, which is a bit odd. It would make more sense if the file-writing method could be used as the stream's terminal operation, within something like forEach.
Unfortunately, most things that write throw IOException, which isn't permitted by the Consumer functional interface that forEach expects. But PrintWriter is different. At least, its writing methods don't throw checked exceptions, although opening one can still throw IOException. Here's how it could be used.
Stream<String> stream = ... ;
try (PrintWriter pw = new PrintWriter("output.txt", "UTF-8")) {
stream.map(s -> s.replaceAll("foo", "bar"))
.forEachOrdered(pw::println);
}
Note the use of forEachOrdered, which prints the output lines in the same order in which they were read, which is presumably what you want!
If you're reading lines from an input file, modifying them, and then writing them to an output file, it would be reasonable to put both files within the same try-with-resources statement:
try (Stream<String> input = Files.lines(Paths.get("input.txt"));
PrintWriter output = new PrintWriter("output.txt", "UTF-8"))
{
input.map(s -> s.replaceAll("foo", "bar"))
.forEachOrdered(output::println);
}

replacing text in a printstream

Is it possible to have a regexp replace in a printstream?
I have a piece of code that logs all text that is shown in my console windows but it also logs ANSI escape codes.
I have found this regexp "s:\x1B\[[0-9;]*[mK]::g" to remove them but that only works with strings.
Is there a way to apply a regex replace to a constant stream of strings and filter out the ANSI escape codes?
If possible, dumb it down as much as possible, I am still a newbie when it comes to programming, I am just building upon a already program.
EDIT:
I have this code which I found somewhere else on stack overflow, this allows me to stream to a logfile and to the console at the same time.
This is what I use and then I set the out to tee after this.
Logging tee = new Logging(file, System.out);
.
package com.md_5.mc.chat;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
public class Logging extends PrintStream
{
private final PrintStream second;
public Logging(OutputStream main, PrintStream second)
{
super(main);
this.second = second;
}
public void close()
{
super.close();
}
public void flush()
{
super.flush();
this.second.flush();
}
public void write(byte[] buf, int off, int len)
{
super.write(buf, off, len);
this.second.write(buf, off, len);
}
public void write(int b)
{
super.write(b);
this.second.write(b);
}
public void write(byte[] b) throws IOException
{
super.write(b);
this.second.write(b);
}
}
Create create a subclass of FilterOutputStream, say RegexOutputStream. This class should buffer all data written to it (from the different write(...) methods). In the flush() method, it should apply the regex and then write the result to the underlying OutputStream.
Next, instantiate the PrintWriter to write to the RegexOutputStream. This way you don't need to alter the behaviour of the PrintWriter class. In case you don't want the filtering anymore, you can just take the RegexOutStream out of the chain, and everything will work again.
Note that, depending on how you use the PrintWriter, this might cause the RegexOutputStreams buffer to get quite big. If you create the PrintWriter to autoflush, it will flush after every line and after every byte array. See its JavaDoc for details.
You could subclass the print stream in question and perform your regexp replacing prior to calling the appropriate super method? E.g.
public void ExampleStream extends PrintStream {
#Override
public void print(String s) {
super(s.replaceAll(ANSI_PATTERN,""));
}
}
I think that the code in Logging class is not a good approach (at least as it is):
If you have access to the PrintStream source code you might find that the methods currently redefined might not being used at all: the PrintStream#print(...) methods delegate on textOut#write(...) (not on the redefined OutputStream#write(...) ).
Therefore, you should redefine the print(String) and print(char[]) methods in order to effectively filter the output.
There are a few examples of redefined methods in the answers (including further down on this one).
Alternatively, if you just want a PrintStream that filters out the ANSI codes (as I originally understood), then it would be more convenient to implement it on a FilterOutputStream (as mthmulders suggests, as you will have to redefine fewer stuff and will be easier to re-use):
Make a copy of BufferedOutputStream class. Name it however you prefer. (E.g. TrimAnsiBufferedStream)
Then redefine de flushBuffer() method:
private void flushBuffer() throws IOException {
if (count > 0) {
String s = new String(buf, 0, count); // Uses system encoding.
s.replaceAll(ANSI_PATTERN, "");
out.write(s.getBytes());
count = 0;
}
}
When you need to instantiate a PrintStream that replaces ANSI, invoke new PrintStream(new TrimAnsiBufferedStream(nestedStream)).
This is probably not bullet-proof (e.g. whatever may happen with encoding configuration, or if buffer size is not big enough, or flushing options in printstream), but I won't overcomplicate it.
By the way. Welcome kukelekuuk00. Just be sure to read the FAQ and feedback on the answers (we care about you, please reciprocate).

Categories