I have a task to implement a logging method that will take all program content up to logging method call and save it to file. The method should not overwrite already present info in file, but rather add new content to it.
What I need to write:
all program messages and output;
all user inputs in the way they appear on console (the program inquires it several times);
My thought on it is to create a StringBuilder object and start appending everything to it. Once logging method is invoked, ask for a file to save log to and save contents of StringBuilder to it. Then flush StringBuilder and continue to gather information. On second invocation, if the same filename is provided, just append new info gathered by StringBuilder.
However, this means that I will need to place gathering invocations all over the place where program output and user input are. Seems like not very optimal to me.
Are there any ideas on how to reach my goal differently and more optimally?
Thank you in advance.
Best regards,
Vadim
UPDATE: I actually was able to redirect system.out to gather everything to ByteArrayStream and then write to file on demand. But I still don't understand how to do it for inputstream. I don't need to redirect it, I still have to input eveyrthing from keyboard, it's just values that have to make it to logs in correct places. Am still searching for a solution.
Do not reinvent the wheel. Go for a logging framework. There is one integrated into java anyway.
Alternatively you can use log4j, and there are other such frameworks out there.
Related
This might have already been asked before, but I haven't found a solution that quite fits my situation.
I have a program that repeatedly prints questions to the user and waits for user input (all in console). I don't clear the screen after each question/response, so the result is all of the questions and the user's answers just sitting there in the console.
Now my question is how do I take whatever is in the console at that current moment and save it into a text file? The way that my program is currently setup makes it illogical to individually save all of my prints and the user's scanner inputs into a text file.
Is there a way to simply read whatever is in the console at that moment and save it into a text file?
Instead of directly calling the System.out.print methods, you can create your own print method that both outputs to the console and stores what was output into a buffer. Then, you can directly write the buffer to a file when necessary.
Alternatively, System.setOut can be used in conjunction with Apache Commons TeeOutputStream.
I get that this isn't possible to do with normal java, although if there are any libraries out this it would be very useful.
Essentially, I'm designing a console app and running into an issue that when output happens while something is typed in the input line, that input text will move up and appear before the line that just got output. Is it possible to fix this in some form so that the text you are inputting that stays at the bottom?
EX:
I'm typing something as input into my commandline app, and then the program prints something WHILE I'm typing - this causes what was originally on the input line to be scrolled up with whatever the output text was. When you are trying to type something in this can obviously be detrimental. I know it's possible to prevent this.. (Other programs have done it... EX: Minecraft Server)
(If I need to be more descriptive I can.)
You could use the help of threads. One that listens to user input, the other process the actual output. This problem is similar to basic race condition problems when multiple threads attempt to read and write to a shared resource.
Your shared resource is that console. You need to keep the Input/Output operations synchronized. Have a look at race condition.
I'm wondering the best method for my program to determine if a file has been appended or completely changed.
What I am currently doing is using a LogIOThread I wrote that is using a FileInputStream.avail to check if a file has been appended. If so, I am appending to a non-editable JTextArea (actually a modified JTextArea with variable scroll features). My end-game was to have a autoscrolling JTextArea that is basically scrolling a log4j outputted logfile. This is working great for me right now. I'd like to adapt this to a non-log files.
What I would like to add to the LogIOThread is a monitor that will check if the file contents changed rather than just have new appended text. The first use case I am trying to solve is the file gets rewritten mid run. At the most basic level I figured I could use this function to reload my JTextArea close and reopen the FileInputStream, and start over if the file get overwritten.
I figured while I was doing that I might want to make it more robust to handle the second use case of mid-file insertions, like a properties file change. I figured I could get the textArea to do a line replace if I can figure out if a line changed.
I have a requirement (not set by me) to use Java6, so some of the new nio FileWatcher's are no good for me. Notifiers in general seem counter productive as I'm catching appends via FileInputStream. This also led me to discount other libs such as Commons and jnotify. I could be wrong though, and maybe FileInputStream.avail is not the best way for me anymore.
My first thought was that I could store the file size, and check if it drastically changed (to a value less than stored). Since a new created log file would need a fresh textArea, this doesn't seem to bad, and solves my first use case. This would not work for the second use case of a specific value change in the file. It also might be problematic for a file that gets recreated with a consistent size while my IOThread is sleeping, although I doubt it's likely.
My second thought was that I could continually check the file modified time, and if there is no appendable text, I would reread the file and do a line comparison? I would need to do this anyway if I'm going to change a line in the textArea unless I reload it every time. This seems horribly inefficient though.
Any suggestions? I'm not opposed to changing how the LogIOThread works if there is a suggestion to get new text and changes with something better than an avail + file modification check combo.
If the file size decreases it has certainly been overwritten. However it may also be overwritten with something as large or larger, so the converse does not hold.
Don't use available() as a surrogate for File.length(). See the Javadoc. That's not what it's for.
How about creating an intermediate OutputStream that reads the log data, makes it available to the JTextField and then routes that data to the file?
I have two threads - one awaits for input and the other is printing the debugging info.
However only one console window, so I can't type 'exit' (or whatever to stop the process), because System.out.println constantly prints the stuff. Can I have two separate console windows for each?
P.S. I wouldn't want to use Swing just for this purpose - there must be a way.
The only way I could think of would be to have two difference processes and a link betweeen the two processes. But I don't have a clue as to how to do that. Perhaps your best bet is to use the JOptionPane class.
While you stated that you don't want to use Swing, I believe that JOptionPane would be the best option for you. Simply using JOptionPane.showInputDialog is a fast way to solve your issue. Here's a link to JOptionPane's JavaDoc.
If you really can't use Swing, there's always the option to press Ctrl + C to stop the process.
A final option would be to buffer the output and only write it after the input. After you receive input, you would flush the buffer and then deal with the input. In this manner, you would prevent the application from closing before the buffer is flushed. There are two ways to do this:
You can use a BufferedWriter with a very large size (maybe 100,000?) and store this as a static variable. Instead of calling System.out.println(), you could call MyClass.out.println()
You could override System using System.setOut(). You would create your own PrintWriter that would take any input and send it to a LinkedList (or your own LinkedList designed for chars, if you choose). I suggest you use a linked list because appending is O(1) for a linked list while appending is O(n) for an array list.
Edit:
As for hmjd's suggestion (file writing), you would do that like this:
System.setOut(new FileWriter(new File(myFileName)));
Log to a file then go into another window and tail the file (in unix/mac use "tail -f filename", in another os--install unix/cygwin!)
This keeps your log separate from your console and makes it persistent as well.
There are a lot of logging utilities out there that will help with this and will even help a bit more by telling you what file a given line is coming from.
Your question is similar to this one, so I think the answer is the same. However, maybe this question might be right for you.
Just a quick one here.
What are the benefits of using java.io.Console as opposed to using a BufferedReader wrapping an InputStreamReader for System.in?
Why would I use it?
Thanks for any advice!
Because it's code that is already written for you...no need to re-invent the wheel. Chances are, you're not going to get it any better than it already is.
You can use java.io.Console to present an interactive command-line to the user. You could do all that with System.in yourself, but you would have to implement things like noticing when the input was done, or readPassword, etc.
See java.io.Console is finally here!
One of the most popular feature
requests for J2SE in recent times has
been the request to improve console
support and provide a way to enter
passwords with echo disabled.
Developers know this feature 4050435
as it has been skulking in the Top 25
RFEs list for some time.
java.io.Console only works when you start a Java program from a command line without redirecting STDIN/STDOUT.
The main advantage I see with Console over System.in is that you have the readPassword() method, which won't echo the characters typed by the user (I couldn't find a way to do this with System.in).
You also have readLine() which will present a prompt and read a single line. You don't have to create your own LineNumberReader.
But, if you want your Java program to be able to read from STDIN when it's redirected from a file or pipe, you still have to use System.in.
Another trick I'm pretty sure you won't get with Console--I created my own input and output streams and replaced System.in/out with them. My implementation of the stream appended to a log file as well as echoing to the screen.
When I turned on my poor-man's "Debug Info", I could even have it tell me what program/line the sysout came from (It was slow though. It created an exception and examined the appropriate stack entry so it was off by default)
java.io.Console is used to take and read input from the user at runtime and output are displayed after processing the input from user.
For more and detailed information visit https://www.examsmyantra.com/article/58/java/java-io---console-input-and-output