0

I have the following method:

public void writeToFile(
  String id, 
  String no, 
  int systol, 
  int diastol, 
  int pulsDiff, 
  double speedAvg, 
  double spread
) { 
  String line = 
    id + "\t" + no + "\t" + systol + "/" + diastol + "\t" + pulsDiff 
    + "\t" + speedAvg + "\t" + spread + "\r\n";

    File fil = new File("resultat.txt");
    BufferedWriter writer = null;
    try { 
      writer = new BufferedWriter(new FileWriter(fil, true)); 
      writer.write(line); 
      writer.close();
    } catch (Exception e) {
      System.err.println("Fejl: " + e.getMessage());
    }

Could this have been done in different ways? With some different methods? And what are the advantages by doing so?

Im trying to understand the advantage of having a bufferedWriter. I'm still at the beginning and I'm trying to understand this sentence:"

In general, a Writer sends its output immediately to the underlying character or byte stream. Unless prompt output is required, it is advisable to wrap a BufferedWriter around any Writer whose write() operations may be costly, such as FileWriters and OutputStreamWriters. For example,

 PrintWriter out    = new PrintWriter(new BufferedWriter(new 
     FileWriter("foo.out")));   

will buffer the PrintWriter's output to the file. Without buffering, each invocation of a print() method would cause characters to be converted into bytes that would then be written immediately to the file, which can be very inefficient.

Especially the "In general, a Writer sends its output immediately to the underlying character or byte stream" part.

StarsSky
  • 6,721
  • 6
  • 38
  • 63
user3161344
  • 83
  • 1
  • 7

4 Answers4

4

Since you're writing a single string to the writer, buffering is useless in this case.

What should really be fixed, though, is the exception handling and the way you're closing the writer. The caller should be warned, using an exception, if the write or the close was not successful, instead of simply logging an error and continuing as if nothing happened.

And the writer should be closed in a finally block, or using the try-with-resources construct, to make sure it's always closed.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Im not quite sure of what you mean. Im writing 7 strings to every line in the .txt document. How should the caller be warned, and what difference does it make? Im not quite sure of what a finally block is, and why the writer should be closed in one. Isn't it closed when I just write:" writer.close(); "? – user3161344 Jan 05 '14 at 11:09
  • There is a single write call to the writer: `writer.write(line);`. After this call, the writer is closed immediately. So buffering is useless. You could write this line directly to the underlying FileWriter directly. The caller should be warned by making the method throw IOException rather than catching it. Reac a tutorial about exceptions. The difference is that the caller would know that a problem happened and could tell the end user (by showing a dialog box, printing a message, or whatever). – JB Nizet Jan 05 '14 at 11:21
  • So I don't need to use a writer.close(); since it's already closed after writer.write(line); ? But it should already be printing a error msg to the end user by System.err.println? Or am I wrong? – user3161344 Jan 05 '14 at 11:39
  • I never said that. On the contrary, I said to put the close() in a finally block to make sure it's always executed. What I said was that buffering was unnecessary because a single write is done. To make an analogy: packing 10 books in a box is easier to transport them. But if you have a single book to transport, packing it in a box is unnecessary: transporting the book directly is as easy and faster. – JB Nizet Jan 05 '14 at 12:52
  • Regarding the error message: this method's responsibility is to write into a file. Not to interact with the user. Let's say you use this method 10 times in a loop: you want the loop to stop as soon as a write fails. You don't want the loop to continue and write 10 times the same error message if the first write fails. – JB Nizet Jan 05 '14 at 12:52
  • So the program actually continues even if there is an error in the filewriting? – user3161344 Jan 05 '14 at 13:18
  • Of course, since you catch the exception. – JB Nizet Jan 05 '14 at 14:51
2

Imagine that you're a Java instruction that talks to an operating system. Without buffering, the situation is like (much simplified):

Java -> OS: Hello, operating system, I'd like to write character c to file F
OS -> HDD : Hello, disk, please append character c to file F
HDD -> OS after a few milliseconds : I'm done.
OS -> Java : Done

If you write many characters to a file, this communication isn't necessary - they're still talking about the same, which is waste of time! That's why we use buffers. See how the situation changes :

Java -> OS: Hello, operating system, I'd like to write bunch of characters c[] to file F
OS -> HDD : Hello, disk, please append characters c[] to file F
HDD -> OS after a few tens of milliseconds : I'm done.
OS -> Java : Done

Period. The whole machinery, all the disk seeks et cetera, is invoked only once.

Danstahr
  • 4,190
  • 22
  • 38
  • so what exatcly buffers do? It skips all boilerplate operations and use only once operation? – solvator Jan 05 '14 at 11:09
  • Must say I really liked this explanation :) But lets say that the situation is the same as in part 2, where I want to write many chars to a file, but this time I have no buffer. Will the HDD take every single char instead of a whole array? – user3161344 Jan 05 '14 at 11:17
  • @user3161344 Yes, exactly. And it repeats all the time the same operation. – solvator Jan 05 '14 at 11:18
  • The second step in the above conversation is imaginary. The sequence starts with a system call from Java to the operating system, and ends with the system call returning. There are no other interactions between the operating system and the application, except in the case of asynchronous I/O which isn't the topic here. – user207421 Jan 24 '14 at 03:58
  • @EJP : I understand your point, but, as I stated in the first paragraph, it's only a demonstration of principles, not a precise description of the whole IO process. – Danstahr Jan 29 '14 at 17:36
1

The advantage of using BufferedReader or BufferedWriter is that is reduces the number of physical reads from and writes to the disk. It makes use of a buffering system and performs reading/writing all at once. Hence there is more efficiency. You can try reading/writing a large file with and without using BufferedReader/BufferedWriter and see the difference.

Hungry Blue Dev
  • 1,313
  • 16
  • 30
  • So could one say it's more time efficient? I mean if I have a large file it would go way faster with a BufferedReader? And if I need to write a lot down in a .txt file it would go a lot faster with a BufferedWriter? – user3161344 Jan 05 '14 at 11:11
  • Well, from my personal experience, I can tell that it can **at least** twice as fast. I copied and pasted a file of size ~80 mb with and without it. Result: With => 9 seconds; Without => 21 seconds. – Hungry Blue Dev Jan 05 '14 at 11:14
  • @user3161344 I think it should be faster, because you make only 1 call instead of xxx calls to your memory management. So it should be more faster. – solvator Jan 05 '14 at 11:16
  • So in this case where my resultat.txt is only like 30 bytes, the BufferedWriter won't make any difference? – user3161344 Jan 05 '14 at 11:20
  • Well, the difference is a few _milli-seconds_ in your case. It's up to you. – Hungry Blue Dev Jan 05 '14 at 11:21
  • 2
    @ambigram_maker: it would be more efficient if you wrote many times to the buffered writer, because, for example, 1000 buffered writes would translate to only 2 or 3 physical writes. But here, there is a single call to write(), which will translate to a single physical write. Doing the physical write directly would thus actually be slightly more efficient. – JB Nizet Jan 05 '14 at 11:24
  • By the way. Could I use a Scanner instead of a BufferedWriter/FileWriter? And what are the advantages by doing so? Or is the Scanner only for when I use BufferedReader/FileReader? – user3161344 Jan 05 '14 at 12:06
  • 1
    Read the javadoc of Scanner. It can't be used to write anything. – JB Nizet Jan 05 '14 at 12:56
0

If you use concatenation by the + operators, you actuall create many strings until you get the final result: "a" + "b" + "c" + "d" mean that you first have "ab", then you want to add another char to get "abc" and in the end you have another addition to get "abcd".

The second option is your way to overcome this inefficiency.

EDIT

My answer talks generally about string concatenation. As mentioned in the reference given by boxed__l in his comment, in some cases there might be optimizations and then concatenation is done by StringBuilder (even if it is not done explicitly). However, there are cases (e.g., when the concatenation is done in a loop), when it matters and optimizations by the compiler are not possible.

Gari BN
  • 1,635
  • 2
  • 17
  • 31
  • @JBNizet Why not? I mean - using streams it is more efficient to concatenate many strings - no? – Gari BN Jan 05 '14 at 11:09
  • 1
    Concatenating strings like this doesn't create many strings. It uses a single StringBuilder, appends everything, and then calls toString(). – JB Nizet Jan 05 '14 at 11:22
  • @JBNizet Can you give me some references? I didn't know that s1+s2+s3+s4+... is actually done using StringBuilder. – Gari BN Jan 05 '14 at 11:30
  • 1
    @GariBN [SO question](http://stackoverflow.com/questions/1532461/stringbuilder-vs-string-concatenation-in-tostring-in-java) – boxed__l Jan 05 '14 at 11:57
  • 2
    See http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.1, which says that this optimization is authorized, and use javap -c SomeExample.class to disassemble the byte-code produced by such code and see that this optimization is done by the compiler. – JB Nizet Jan 05 '14 at 12:21