writing string to outputstream in java

I have a simple servlet class returns CSV file to a client (browser). When I tried to write string to stream. Initially I have followed example A) however I noticed that subset of expected data are appended.

Let's say I expect exact 100 records to be captured in a csv file. Each record represent "first name/last name/age". In the example A) I got 120. First 100 records are correct but subset of 100 in this case 20 (duplicates) are appended.

example A)

public void returnCSV(HttpServletResponse resp, String data) {
    ServletOutputStream out = resp.getOutputStream();
    InputStream in = new ByteArrayInputStream(data.getBytes("UTF-8"));
    byte[] bytes = new byte[4096];
    while (in.read(bytes,0,4096) != -1) {
        out.write(bytes,0,4096);
    }
    in.close();
    out.flush();
    out.close();
 }

After reading more threads in regards to converting string to stream. I decided to follow example B) which produced correct output 100 records. But I do not understand why first example A) would add duplicate data.

example B)

public void returnCSV(HttpServletResponse resp, String data) {
    ServletOutputStream out = resp.getOutputStream();
    out.write(data.getBytes("UTF-8"));        
    out.flush();
    out.close();
 }
Jon Skeet
people
quotationmark

Look at this loop:

while (in.read(bytes,0,4096) != -1) {
    out.write(bytes,0,4096);
}

However much data is read by read, you're always writing out 4096 bytes. You only want to copy the same amount of data you've read, e.g.

int bytesRead;
while ((bytesRead = in.read(bytes)) != -1) {
    out.write(bytes, 0, bytesRead);
}

There are plenty of third-party libraries which have code to copy from an input stream to an output stream, mind you - and you should be using try-with-resources statements to close the streams anyway.

Additionally, instead of calling getOutputStream, you should be calling ServletResponse.getWriter, potentially after calling ServletResponse.setCharacterEncoding to ensure that it's using UTF-8. Then you can just call:

writer.write(data);

Writers are designed to write text data; output streams are designed to write binary data. You can create a writer on top of a stream using OutputStreamWriter, but as the servlet API will do that for you, you might as well let it...

people

See more on this question at Stackoverflow