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();
}
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...
See more on this question at Stackoverflow