I've reduced your question to its essence:

public class Test {
  static byte[] bytes = new byte[10_000_000];
  static {
    for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) (i%100+32);
  }
  public static void main(String[] args) throws Exception {
    writer(true);
    writer(false);
    stream(true);
    stream(false);
  }

  static void writer(boolean flush) throws IOException {
    Writer out = new FileWriter("output.txt");
    long a = System.currentTimeMillis();
    for (byte j : bytes) {
      out.write(j);
      if (flush) out.flush();
    }
    out.close();
    System.out.println("FileWriter with" + (flush? "":"out") + " flushing: " +
        (System.currentTimeMillis() - a));
  }
  static void stream(boolean flush) throws IOException {
    OutputStream out = new FileOutputStream("output.txt");
    long a = System.currentTimeMillis();
    for (byte j : bytes) {
      out.write(j);
      if (flush) out.flush();
    }
    out.close();
    System.out.println("FileOutputStream with" + (flush? "":"out") + " flushing: " +
        (System.currentTimeMillis() - a));
  }
}

Notes:

  • properly closing the resources when done;
  • double loop replaced by single loop, but a larger array;
  • avoid writing control characters to evade autoflush behavior;
  • only using byte array since you are testing only one method in all cases: write(int). Therefore it makes no difference whether you are using bytes or chars;
  • removed everything except a FileWriter and a FileOutputStream because all other cases boil down to these two;
  • testing both writer and output stream in two modes: flush after each write, and don't flush at all until close.

Now, when you run this, you'll get output like the following:

FileWriter with flushing: 28235
FileWriter without flushing: 828
FileOutputStream with flushing: 23984
FileOutputStream without flushing: 23641

So, what's the lesson?

  • all writers are buffered because internally they delegate to StreamEncoder which is itself buffered;
  • FileOutputStream is not buffered;
  • non-buffered writing byte-by-byte is very slow.

Good practices demand that you always do buffered writing: either using buffered sinks, or maintaining an explicit buffer on your side.

Answer from Marko Topolnik on Stack Overflow
Top answer
1 of 1
5

I've reduced your question to its essence:

public class Test {
  static byte[] bytes = new byte[10_000_000];
  static {
    for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) (i%100+32);
  }
  public static void main(String[] args) throws Exception {
    writer(true);
    writer(false);
    stream(true);
    stream(false);
  }

  static void writer(boolean flush) throws IOException {
    Writer out = new FileWriter("output.txt");
    long a = System.currentTimeMillis();
    for (byte j : bytes) {
      out.write(j);
      if (flush) out.flush();
    }
    out.close();
    System.out.println("FileWriter with" + (flush? "":"out") + " flushing: " +
        (System.currentTimeMillis() - a));
  }
  static void stream(boolean flush) throws IOException {
    OutputStream out = new FileOutputStream("output.txt");
    long a = System.currentTimeMillis();
    for (byte j : bytes) {
      out.write(j);
      if (flush) out.flush();
    }
    out.close();
    System.out.println("FileOutputStream with" + (flush? "":"out") + " flushing: " +
        (System.currentTimeMillis() - a));
  }
}

Notes:

  • properly closing the resources when done;
  • double loop replaced by single loop, but a larger array;
  • avoid writing control characters to evade autoflush behavior;
  • only using byte array since you are testing only one method in all cases: write(int). Therefore it makes no difference whether you are using bytes or chars;
  • removed everything except a FileWriter and a FileOutputStream because all other cases boil down to these two;
  • testing both writer and output stream in two modes: flush after each write, and don't flush at all until close.

Now, when you run this, you'll get output like the following:

FileWriter with flushing: 28235
FileWriter without flushing: 828
FileOutputStream with flushing: 23984
FileOutputStream without flushing: 23641

So, what's the lesson?

  • all writers are buffered because internally they delegate to StreamEncoder which is itself buffered;
  • FileOutputStream is not buffered;
  • non-buffered writing byte-by-byte is very slow.

Good practices demand that you always do buffered writing: either using buffered sinks, or maintaining an explicit buffer on your side.

🌐
Narkive
comp.lang.java.help.narkive.com › dKrnNGj0 › what-s-the-diff-printwriter-vs-outputstreamwriter
What's the diff PrintWriter vs. OutputStreamWriter ?
It explicitly converts from characters to bytes with an OutputStreamWriter. It uses a BufferedOutputStream (like the BufferedWriter, but on bytes instead of characters) to batch writes. Finally, the whole thing goes to a file via a FileOutputStream. By the Way, using a buffer is generally a ...
🌐
Oracle
docs.oracle.com › javase › 7 › docs › api › java › io › PrintStream.html
PrintStream (Java Platform SE 7 )
A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method.
🌐
Programiz
programiz.com › java-programming › printstream
Java PrintStream (With Examples)
we have created a print stream that will write formatted data to the file represented by FileOutputStream · the autoFlush is an optional boolean parameter that specifies whether to perform auto flushing or not ... Note: In both the case, the PrintStream write data to the file using some default character encoding.
Top answer
1 of 2
54

I don't see where you are closing the file. I don't see you reading anything either.

I assume you want to append to the file instead of overwriting it each time. In that case you need to use the append option of FileOutputStream as this is not the default behaviour.

PrintStream writetoEngineer = new PrintStream(
     new FileOutputStream("Engineer.txt", true)); 

BTW: e.toString() + " " is almost the same as e + " " except the latter doesn't throw an exception if e is null.

2 of 2
3

Since the code given code snippet isn't a Self Contained Compilable Example (it is Simple though), I can just guess that the PrintStream is created inside the loop, per each iteration over the Engineer collection. That would cause the file to be truncated as indicate in PrintStream's constructor javadoc:

Parameters:

file - The file to use as the destination of this print stream. 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.

try this example code:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;


public class PrintEngineers {

    public static class Engineer {
    
        private final String firstName;
        private final String surName;
        private final int weeklySal;
    
        public Engineer(String firstName, String surName, int weeklySal) {
            super();
            this.firstName = firstName;
            this.surName = surName;
            this.weeklySal = weeklySal;
        }

        public int calculateMonthly() {
            return weeklySal * 4; // approximately
        }
    
        @Override
        public String toString() {
            return firstName + " " + surName;
        }
    }

    /**
     * @param args
     * @throws FileNotFoundException 
     */
    public static void main(String[] args) throws FileNotFoundException {
    
        Engineer e1 = new Engineer("first1", "sur1", 100);
        Engineer e2 = new Engineer("first2", "sur2", 200);
        Engineer e3 = new Engineer("first3", "sur3", 300);

        List<Engineer> engineers = new ArrayList<>(3);
        engineers.add(e1);
        engineers.add(e2);
        engineers.add(e3);

        // instanciate PrintStream here, before the loop starts
        PrintStream writetoEngineer = new PrintStream(new File("Engineer.txt"));
        for (Engineer engineer : engineers) {
            // new PrintStream(...) here truncates the file (see javadoc)               //This is not append.Only print.Refresh file on each item 
            writetoEngineer.append(engineer.toString()).append(' ')
                        .append("" + engineer.calculateMonthly()).append('\n'); 
        
        }
    }

}
🌐
Jenkov
tutorials.jenkov.com › java-io › printstream.html
Java IO: PrintStream
September 3, 2015 - That means that the try-with-resources block will not automatically close this FileOutputStream instance. However, when the PrintStream is closed it will also close the OutputStream instance it writes to, so the FileOutputStream instance will get closed when the PrintStream is closed.
Find elsewhere
🌐
Coderanch
coderanch.com › t › 655887 › java › PrintWriter-FileOutputStream
PrintWriter and FileOutputStream (Beginning Java forum at Coderanch)
PrintWriter is used to write data as text into files while FileOutputStream is used to write in binary. ex: consider Gives output : (Image Tag somehow not displaying image ... Hence Url ) http://postimg.org/image/dzbugcyv9/ However , If I use FileOutputStream I get binary data which is not ...
Top answer
1 of 7
38

According to coderanch.com, if we combine the answers we get:

FileWriter is the character representation of IO. That means it can be used to write characters. Internally FileWriter would use the default character set of the underlying OS and convert the characters to bytes and write it to the disk.

PrintWriter & FileWriter.

Similarities

  1. Both extend from Writer.
  2. Both are character representation classes, that means they work with characters and convert them to bytes using default charset.

Differences

  1. FileWriter throws IOException in case of any IO failure, this is a checked exception.
  2. None of the PrintWriter methods throw IOExceptions, instead they set a boolean flag which can be obtained using checkError().
  3. PrintWriter has an optional constructor you may use to enable auto-flushing when specific methods are called. No such option exists in FileWriter.
  4. When writing to files, FileWriter has an optional constructor which allows it to append to the existing file when the "write()" method is called.

Difference between PrintStream and OutputStream: Similar to the explanation above, just replace character with byte.

PrintWriter has following methods :

close()
flush()
format()
printf()
print()
println()
write()

and constructors are :

File (as of Java 5)
String (as of Java 5)
OutputStream
Writer

while FileWriter having following methods :

close()
flush()
write()

and constructors are :

File
String 

Link: http://www.coderanch.com/t/418148/java-programmer-SCJP/certification/Information-PrintWriter-FileWriter

2 of 7
12

Both of these use a FileOutputStream internally:

public PrintWriter(File file) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
     false);
}



public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}

but the main difference is that PrintWriter offers special methods:

Prints formatted representations of objects to a text-output stream. This class implements all of the print methods found in PrintStream. It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams.

Unlike the PrintStream class, if automatic flushing is enabled it will be done only when one of the println, printf, or format methods is invoked, rather than whenever a newline character happens to be output. These methods use the platform's own notion of line separator rather than the newline character.

Top answer
1 of 3
17

From java docs

A DataOutputStream lets an application write primitive Java data types to an output stream in a portable way. An application can then use a data input stream to read the data back in.

PrintWriter Prints formatted representations of objects to a text-output stream. This class implements all of the print methods found in PrintStream. It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams.

In one sentence the difference is:

OutputStreams are meant for binary data. Writers (including PrintWriter) are meant for text data

2 of 3
1

PrintWriter converts everything to Ascii format. For example:

PrintWriter pw = new PrintWriter(new File("./test.txt"));        
        for (Integer word: words) {
            pw.println(word);
        }

in this block of code, by calling pw.printin(word); no matter what the type of word is (which is integer here), program converts it to ASCII format and stores it. As a result, when we want to retrieve that stored data and read it again, program have to do another type changing from text to original format! -which is not good in term of time efficiency! For instance, if that word is an integer, after storing that into a file (which is text now), program has to change its format from String to integer when it is going to retrieve that!

But, DataOutPutStream makes everything much easier since it stores the data into bytes by keeping data type. So, when we run bellow block, program stored integer as byte and when it want to retrieve that it does not need any change of type. It's stored as integer and retrieved as integer too. So, it is much faster!

DataOutputStream dos = new DataOutputStream(
            new FileOutputStream(new File("test2.txt")));

    for (Integer word: words) {
        dos.writeUTF(word);   
 }
dos.close();
Top answer
1 of 3
29

PrintStream was the original bridge to deal with encoding characters and other datatypes. If you look at the javadoc for java.io.OutputStream you'll see methods only for writing two distinct data types: byte and int.

In early versions of the JDK (1.0.x), when you wanted to write characters, you could do one of two things, write bytes to an output stream (which are assumed to be in the system default character set):

outputStream.write("foobar".getBytes());

or wrap another outputStream in a PrintStream:

PrintStream printStream = new PrintStream(outputStream);
printStream.write("foobar");

See the difference? PrintStream is handling the character conversion to bytes, as well as encoding (the constructor call above uses the system default encoding, but you could pass it as a parameter). It also provides convenience methods for writing double, boolean, etc....

In fact System.out and System.err are defined as PrintStream instances.

Along comes JDK 1.1, and they realize they need a better way to deal with pure character data, since PrintStream still has the byte based methods for writing. So they introduced the Writer abstract class to deal strictly with char, String and int data.

PrintWriter adds methods for other types like double, boolean, etc...

Nowadays PrintWriter also has format() / printf() methods for format printing, etc...

As a general rule, if you're writing character data, use Writer instances. If you're writing binary (or mixed) data use OutputStream instances.

2 of 3
10

From the Javadoc for PrintWriter:

Prints formatted representations of objects to a text-output stream. This class implements all of the print methods found in PrintStream. It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams.

Think of it this way: a PrintStream sits on top of some OutputStream. Since output streams deal with bytes rather than characters, the PrintStream must take responsibility for encoding characters into bytes. The OutputStream 'merely' writes the bytes out to a file/console/socket whatever.

A PrintWriter, on the other hand, sits on top of a Writer. Since the Writer is responsible for encoding characters into bytes, the PrintWriter does not do encoding. I just knows about newlines etc. (Yes, PrintWriters do have constructors that take Files and OutputStreams, but those are simply conveniences. For example, PrintWriter(OutputStream).

Creates a new PrintWriter, without automatic line flushing, from an existing OutputStream. This convenience constructor creates the necessary intermediate OutputStreamWriter, which will convert characters into bytes using the default character encoding.

BTW, In case you are thinking that the PrintWriter really doesn't have much utility, remember that both PrintWriter and PrintStream absorb IOExceptions from printing logic.

Top answer
1 of 2
4

Files contain bytes. Always.

Characters are written into files by transforming characters into bytes, using an encoding. Many such encodings exist. For example, ASCII allows transforming 128 different characters to bytes. UTF-8 allows encoding any Unicode character to bytes. The two encodings, for example, transform the character '1' into the byte 49. '2' would be transformed into the byte 50.

When using a PrintWriter with a file name as argument, the PrintWriter actually opens a FileOuptutStream to write bytes to the file. When you write characters to the PrintWriter, the PrintWriter transforms characters to bytes using an encoding, and then write those bytes to the FileOutputStream, which writes the bytes to the file.

So, for example, if you use the following program:

public class Main {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream(new File("data")) ; 
        for(int i = 49; i <= 58; ++i)
            fos.write(i);
        fos.close();
    }
}

and then open the file with a text editor, you should see 123456789 in the file, because the code writes the byte representation (in ASCII or UTF8) of those characters directly.

2 of 2
2

Look at the docs.

From FileOutputStream.html#write(int):

Writes the specified byte to this file output stream.

From PrintWriter.html#print(int):

Prints an integer. The string produced by String.valueOf(int) is translated into bytes according to the platform's default character encoding, and these bytes are written in exactly the manner of the write(int) method.

That is, this method will write numbers as you see them. The other one writes bytes. The byte value 9 is not the number 9, but an unreadable character.

🌐
DocStore
docstore.mik.ua › orelly › java › fclass › ch06_02.htm
[Chapter 6] 6.2 Output Streams and Writers
The OutputStream class is an abstract class that defines methods to write a stream of bytes sequentially. Java provides subclasses of the OutputStream class for writing to files and byte arrays, among other things. Other subclasses of OutputStream can be chained together to provide additional ...
Top answer
1 of 6
135

This might sound flippant, but PrintStream prints to an OutputStream, and PrintWriter prints to a Writer. Ok, I doubt I'll get any points for stating the obvious. But there's more.

So, what is the difference between an OutputStream and a Writer? Both are streams, with the primary difference being a OutputStream is a stream of bytes while a Writer is a stream of characters.

If an OutputStream deals with bytes, what about PrintStream.print(String)? It converts chars to bytes using the default platform encoding. Using the default encoding is generally a bad thing since it can lead to bugs when moving from one platform to another, especially if you are generating the file on one platform and consuming it on another.

With a Writer, you typically specify the encoding to use, avoiding any platform dependencies.

Why bother having a PrintStream in the JDK, since the primary intent is to write characters, and not bytes? PrintStream predates JDK 1.1 when Reader/Writer character streams were introduced. I imagine Sun would have deprecated PrintStream if only for the fact it is so widely used. (After all, you wouldn't want each call to System.out to generate a deprecated API warning! Also, changing the type from PrintStream to PrintWriter on the standard output streams would have broken existing applications.)

2 of 6
22

Since JDK 1.4 it's possible to specify the character encoding for a PrintStream. Thus, the differences between PrintStream and PrintWriter are only about auto flushing behavior and that a PrintStream cannot wrap a Writer.

Top answer
1 of 5
33

No, you only need to close the outermost stream. It will delegate all the way to the wrapped streams.

However, your code contains one conceptual failure, the close should happen in finally, otherwise it's never closed when the code throws an exception between opening and closing.

E.g.

public static void main(String args[]) throws IOException { 
    PrintStream ps = null;

    try {
        ps = new PrintStream(new FileOutputStream("myfile.txt"));
        ps.println("This data is written to a file:");
        System.out.println("Write successfully");
    } catch (IOException e) {
        System.err.println("Error in writing to file");
        throw e;
    } finally {
        if (ps != null) ps.close();
    }
}

(note that I changed the code to throw the exception so that you understand the reason of the problem, the exception namely contains detailed information about the cause of the problem)

Or, when you're already on Java 7, then you can also make use of ARM (Automatic Resource Management; also known as try-with-resources) so that you don't need to close anything yourself:

public static void main(String args[]) throws IOException { 
    try (PrintStream ps = new PrintStream(new FileOutputStream("myfile.txt"))) {
        ps.println("This data is written to a file:");
        System.out.println("Write successfully");
    } catch (IOException e) {
        System.err.println("Error in writing to file");
        throw e;
    }
}
2 of 5
8

No , here is implementation of PrintStream's close() method:

public void close() {
    synchronized (this) {
        if (! closing) {
        closing = true;
        try {
            textOut.close();
            out.close();
        }
        catch (IOException x) {
            trouble = true;
        }
        textOut = null;
        charOut = null;
        out = null;
        }
    }

You can see out.close(); which closes output stream.

🌐
Quora
quora.com › Under-which-conditions-are-PrintWriter-and-PrintStream-used-in-Java
Under which conditions are PrintWriter and PrintStream used in Java? - Quora
March 12, 2015 - Answer (1 of 3): Printstream is used when you are going to send file over network or writing it to disk and you are going to operate on streams/bytes not in text based encoding. When it is text/character based file and you are going to write ...