I need to write the same text to multiple files (or streams).
Sometimes I need to use Writer, sometimes a PrintWriter, sometimes a OutputStream...
One way to do this wold be to extend a PrintWriter to have an array of PrintWriters and overridde each method as follows:
class MutiplePrintWriter extends PrintWriter {
private PrintWriter[] outs;
public MutiplePrintWriter(PrintWriter[] outs) { this.out = out; }
public void print(boolean b) { for (PrintWriter out : outs) print(b); }
public void print(char c) { for (PrintWriter out : outs) print(c); }
public void print(char[] s) { for (PrintWriter out : outs) print(s); }
...
}
(and the same for Writer, OutputStream...)
Is there a better alternative?
Is this already implemented in a library?
There are libraries out there already for this. If you can use OSS then grab Apache Commons IO and take a look at the TeeOutputStream class. Here's some sample code illustrating its use:
public class TeeOutputStreamTest {
#Test
public void testPrintToMultipleStreams() throws Exception {
final String fileName1 = "/tmp/fileOne.txt";
final String fileName2 = "/tmp/fileTwo.txt";
final String fileName3 = "/tmp/fileThree.txt";
final TeeOutputStream tos = new TeeOutputStream(new FileOutputStream(
fileName1), new TeeOutputStream(new FileOutputStream(fileName2),
new FileOutputStream(fileName3)));
final PrintWriter writer = new PrintWriter(tos);
writer.println("Hello World");
writer.close();
}
}
You can use TeeOutputStream anywhere a regular OutputStream is accepted, or wrap it in a Writer, depending on whats needed.
You don't need to override all methods in PrintWriter, since all printXyz methods delegate to the basic write methods of the Writer API.
Although: PrintWriter has a constructor PrintWriter(Writer out). So you need to implement only a new Writer with _one_method likes this:
public class MultiWriter implements Writer {
private List<Writer> delegates;
public MultiWriter(List<Writer> delegates){
this.delegates = delegates;
}
public void write(char cbuf[], int off, int len) throws IOException {
for(Writer w: delegates){
w.writer(cbuf, off, len);
}
}
}
use this like this:
PrintWriter myPrinter = new PrintWriter(new MultiWriter(listOfDelegates));
myPrintWriter.println("Hello World!");
This will take care of the Writers.
You can do the same trick using OutputStream. You can also just implement MultiOutputStream, omit MultiWriter and use a delegation chain PrintWriter->OutputStreamWriter->MultiOutputStream. This would be just one method in one class to implement and you get PrintWriter, Writer and OutputStream just for free.
If you can use a Logging Library...
Use a logging library and define multiple appenders in its configuration.
You could use Apache Log4J or LogBack to that effect (I'd recommend LogBack, but to each their own).
If you are forced to use PrintWriter...
The unfortunately your solution is the best.
There's an alternative, but it's not pretty. If you are forced to pass a PrintWriter, short of providing an extension to add to the JRE's trusted libs at load time to replace PrintWriter with a class doing in effect what you suggest, I don't think you have much choice.
Well, actually you could do this easily:
instead of overriding all methods of PrintWriter class, you could override only one method of class Writer:
public void write(char cbuf[], int off, int len);
because all other methods (print(...) and other write(...)-s) use this one:
public void write(char cbuf[], int off, int len) {
for (Writer out : outs) out.write(cbuf, off, len);
}
UPD: also flush() and close() methods.
For OutputStream the same situation with method public void write(int b)
I prefer composition to extension. Here is another option:
public class MultiWriter
{
List<PrintWriter> listPrintWriter = new LinkedList<PrintWriter>;
List<Writer> listWriter = new LinkedList<Writer>;
public void addPrintWriter(final PrintWriter newPrintWriter)
{
listPrintWriter.add(newPrintWriter);
}
public void addWriter(final Writer newWriter)
{
listWriter.add(newWriter);
}
public void write((char cbuf[], int off, int len)
{
if (listPrintWriter != null)
{
for (PrintWriter printWriter : listPrintWriter)
{
printWriter.write(cbuf, off, len);
}
}
if (listWriter != null)
{
for (Writer writer : listWriter)
{
writer.write(cbuf, off, len);
}
}
}
Related
I have class Artical:
first variable is code of artical, second variable is name of article and third is price of article.
public class Artical {
private final String codeOfArtical;
private final String nameOfArtical;
private double priceOfArtical;
public Artical(String codeOfArtical, String nameOfArtical, double priceOfArtical) {
this.codeOfArtical= codeOfArtical;
this.nameOfArtical= nameOfArtical;
this.priceOfArtical= priceOfArtical;
}
public void setPriceOfArtical(double priceOfArtical) {
this.priceOfArtical= priceOfArtical;
}
public String getCodeOfArtical() {
return codeOfArtical;
}
public String getNameOfArtical() {
return nameOfArtical;
}
public double getPriceOfArtical() {
return priceOfArtical;
}
}
I want in main class to write something like:
Artical a1 = new Artical("841740102156", "LG Monitor", 600.00);
new ShowArticalClass(a1).do();
new WriteArticalInFileClass(new File("baza.csv"), a1).do();
so that data in file will be written in format like this:
841740102156; Monitor LG; 600.00;
914918414989; Intel CPU; 250.00;
Those 2 classes ShowArticalClass and WriteArticalInFileClass arent important, those are abstract classes.*
So my question is: How do I set format to look like this, where every line is new Artical.
A very naive implementation can be the following:
Create a class that in turn creates a CSVWriter (assuming you want to write to a CSV). That class will expose a public method allowing you to pass in a path where the desired csv file lives as well as the Artical object you want to write to this file. Using that class you will format your data and write them to the file. An example of this could be:
public class CsvWriter {
private static final Object LOCK = new Object();
private static CsvWriter writer;
private CsvWriter() {}
public static CsvWriter getInstance() {
synchronized (LOCK) {
if (null == writer) {
writer = new CsvWriter();
}
return writer;
}
}
public void writeCsv(String filePath, Artical content) throws IOException {
try (var writer = createWriter(filePath)) {
writer.append(getDataline(content)).append("\n");
}
}
private String getDataline(Artical content) {
return String.join(",", content.getCode(), content.getName(), Double.toString(content.getPrice()));
}
private PrintWriter createWriter(String stringPath) throws IOException {
var path = Paths.get(stringPath);
try {
if (Files.exists(path)) {
System.out.printf("File under path %s exists. Will append to it%n", stringPath);
return new PrintWriter(new FileWriter(path.toFile(), true));
}
return new PrintWriter(path.toFile());
} catch (Exception e) {
System.out.println("An error has occurred while writing to a file");
throw e;
}
}
}
Note that this will take into account where the file provided is already in place (thus appending to it). In any other case the file will be created and written to directly.
Call this write method in a fashion similar to this:
public static void main(String... args) throws IOException {
var artical = new Artical("1", "Test", 10.10);
CsvWriter.getInstance().writeCsv("/tmp/test1.csv", artical);
var artical2 = new Artical("2", "Test", 11.14);
CsvWriter.getInstance().writeCsv("/tmp/test1.csv", artical2);
}
With that as a starting point you can go ahead and modify the code to be able to handle list of Artical objects.
If you really need to support CSV files though I would strongly recommend into looking at the various CSV related libraries that are out there instead of implementing your own code.
How do I write in same text file from different classes in java.
One of the class call method from another class.
I do not want to open BufferedWriter in each class, so thinking if there is a cleaner way to do this ?
So essentially, I want to avoid writing the following code in each class
Path path = Paths.get("c:/output.txt");
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
writer.write("Hello World !!");
}
A good way of doing this is to create a central writing class, that maps from a file name to a reader/writer-object. For example:
public class FileHandler {
private static final Map<String, FileHandler> m_handlers = new HashMap<>();
private final String m_path;
private final BufferedWriter m_writer;
// private final BufferedReader m_reader; this one is optional, and I did not instantiate in this example.
public FileHandler (String path) {
m_path = path;
try {
m_writer = Files.newBufferedWriter(path);
} catch (Exception e) {
m_writer = null;
// some exception handling here...
}
}
public void write(String toWrite) {
if (m_writer != null) {
try {
m_writer.write(toWrite);
} catch (IOException e) {
// some more exception handling...
}
}
}
public static synchronized void write(String path, String toWrite) {
FileHandler handler = m_handlers.get(path);
if (handler == null) {
handler = new FileHandler(path);
m_handlers.put(path, toWrite);
}
handler.write(toWrite);
}
}
Be aware that this behavior does not close the file writers at any point, because you don't know who else is currently (or later on) writing. This is not a complete solution, just a strong hint in a good direction.
This is cool, because now you can "always" call FileHandler.write("c:output.txt", "Hello something!?$");. The FileHandler class could be extended (as hinted) to read files too, and to do other stuff for you, that you might need later (like buffer the content, so you don't have to read a file every time you access it).
So i have tried every thing but the files keeps over writing the first line, i am passing these methods to another class so the three arguments in method add_records are passed through a scanner.
here is the creating/opening method :
public class Io_Files{
private Formatter output;
public void open_file_normal(String filename) throws IOException
{
{
try
{
FileWriter fileWriter = new FileWriter(filename, true);
output = new Formatter(filename);
}
catch(FileNotFoundException fileNotFoundException)
{
System.err.println("Error");
}
}
}
and here is the code for adding record method:
public void add_records(String a, String b, int c) throws FileNotFoundException{
output.format ("[%s, %s, %d]%n", a, b, c);
}
please if you are able to help provide some comments on why and where to put the code so i can learn too.
cheers
Try using
output = new Formatter(fileWriter);
instead of
output = new Formatter(filename);
I have created a class that dynamically compiles, loads in a CustomClassLoader, and executes an in-memory java source (i.e.: without class files) java source by invoking it's main method.
I need to capture the StdOut, StdIn, and StdErr, although it's not possible doing so in my current code. (Compiler API + Classloader + Reflection)
My requirements might be the same as asked in this question - and as suggested by the accepted answer - use java.lang.Process. This is easier if I had physical files available in the file system, but I have not in this case.
I am planning to remove the Classloader + Reflection strategy and use the suggestion instead; although, I'm not familiar in actually redirecting the Std* using the Process class.
How can I do this in Java 7? (Snippets are highly appreciated) Or more importantly, is there a better approach?
Take a backup of the existing outputstream.
PrintStream realSystemOut = System.out;
Set it to other outputstream [ fileOutputStream, or some other streams]
PrintStream overridePrintStream = new PrintStream(new FileOutputStream("log.txt"));
System.setOut(overridePrintStream );
----- process -----
place the actual stream back to System.out
System.setOut(realSystemOut);
Thanks
Java allows you to supply your own PrintStream to override stdout and stderr and a InputStream for stdin.
Personally, I don't like simply throwing away the original stream, cause I tend to only want to redirect or parse it, not stop it (although you could do that as well).
Here is a simple example of the idea...
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
public class RedirectStdOut {
public static void main(String[] args) {
Consumer stdConsumer = new Consumer() {
#Override
public void processLine(StreamCapturer capturer, String text) {
}
#Override
public void processCharacter(StreamCapturer capturer, char character) {
capturer.getParent().print(character);
}
};
StreamCapturer stdout = new StreamCapturer(stdConsumer, System.out);
StreamCapturer stderr = new StreamCapturer(stdConsumer, System.err);
System.setOut(new PrintStream(stdout));
System.setErr(new PrintStream(stderr));
System.out.println("This is a test");
System.err.println("This is an err");
}
public static interface Consumer {
public void processLine(StreamCapturer capturer, String text);
public void processCharacter(StreamCapturer capturer, char character);
}
public static class StreamCapturer extends OutputStream {
private StringBuilder buffer;
private Consumer consumer;
private PrintStream parent;
private boolean echo = false;
public StreamCapturer(Consumer consumer, PrintStream parent) {
buffer = new StringBuilder(128);
this.parent = parent;
this.consumer = consumer;
}
public PrintStream getParent() {
return parent;
}
public boolean shouldEcho() {
return echo;
}
public void setEcho(boolean echo) {
this.echo = echo;
}
#Override
public void write(int b) throws IOException {
char c = (char) b;
String value = Character.toString(c);
buffer.append(value);
if (value.equals("\n")) {
consumer.processLine(this, value);
buffer.delete(0, buffer.length());
}
consumer.processCharacter(this, c);
if (shouldEcho()) {
parent.print(c);
}
}
}
}
Now the StreamCapturer has the ability to echo the output if you want, I've turned it off to demonstrate the use of the Consumer. I would normally use the Consumer to process what is coming through the stream, based on your needs, you can wait for the complete line or process the individual characters...
I have trouble with write txt file from class FileWrite in my java project , if the PRINT() method were in VehicleCollection class , and called in main class - don't have problems. But I want print method be in different class which named FileWrite and called in main method from this class . Here peace of Code . I hope that i write correct question. if i should Explain more about my code I will .
I have 3 Classes 1st class is :
public class VehicleCollection {
private ArrayList<VehicleInterface> arrList = new ArrayList<>();
public ArrayList<VehicleInterface> getArrList() {
return arrList;
}
void setArrList(ArrayList<VehicleInterface> w){
arrList = w;
}
public void getCollection() throws FileNotFoundException, IOException {
Here Add in ArrayLIst...
}
}
Second class is :
public class FileWrite extends VehicleCollection {
FileWrite(ArrayList<VehicleInterface> w){
setArrList(w);
}
public void print() throws FileNotFoundException {
Writer writer = null;
try {
String text = getArrList().toString();
File file = new File("krasiWrite.txt");
writer = new BufferedWriter(new java.io.FileWriter(file));
writer.write(text);
...
}
Third class is main class :
FileWrite fw = new FileWrite();
fw.print();
here Have error:cannot be applied to given types required ArrayList
File writes are usually buffered by the operating system. You must either close() or flush() the writer to make sure that the changes go to disk. If you're done with the file, just close it. A close will automatically flush the buffers.
Since you are already using Java 7, why not use the try-with-resources construct to avoid having to do things like close streams:
try( File file = new File("krasiWrite.txt");
Writer writer = new BufferedWriter(new java.io.FileWriter(file)); )
{
String text = getArrList().toString();
writer.write(text);
writer.flush(); // this lines takes whatever is stored in the BufferedWriter's internal buffer
// and writes it to the stream
}
catch(IOException ioe) {
// ... handle exception
}
// now all resources are closed.