4

I would like to permit the client to download a csv file containing data from a ResultSet. I am using the java API (PLAY! 2.1).

My solution works but is not usable when the ResultSet contains a huge amount of data.

In my controller:

ResultSet rs = st.executeQuery(sql);
String filename = "";
filename = createCSV(rs);.
response().setContentType("text/csv");
response().setHeader("Content-disposition","attachment; filename="+"export.csv");
return ok(new java.io.File("D:\\UTILIS~1\\user\\AppData\\Local\\Temp\\"+filename));

createCSV method:

public static String createCSV(ResultSet _resultSet) {
    String filename = "";
    try{
        ResultSetMetaData meta = _resultSet.getMetaData();

        // CSV file creation 
        File tempDir = new File(System.getProperty("java.io.tmpdir"));
        System.out.println(System.getProperty("java.io.tmpdir"));
        File tempFile = File.createTempFile("test", ".csv", tempDir);
        filename = tempFile.getName();
        FileWriter fileWriter = new FileWriter(tempFile, true);
        System.out.println(tempFile.getAbsolutePath());
        BufferedWriter bw = new BufferedWriter(fileWriter);

        for(int i = 1; i <= meta.getColumnCount(); i++)
        {
            String columnLabel = meta.getColumnName(i);
            bw.write(columnLabel + "|");
        }
        bw.write("\r\n");
        while(_resultSet.next())
        {
            for(int i = 1, count = meta.getColumnCount(); i <= count; i++){
                if (_resultSet.getObject(i) == null)
                    bw.write("null|");
                else
                    bw.write(_resultSet.getObject(i).toString() + "|");
            }
            bw.write("\r\n");
        }
        bw.close();
        tempFile.deleteOnExit();
    } catch(Exception e){
        e.printStackTrace();
    } 
    return filename;
}

To save memory, how can I write to a file and send it to the user using stream.

I think i need to use Chunks but i am not sure how to do it.

Any samples, hints?

maba
  • 47,113
  • 10
  • 108
  • 118
fdubrez
  • 122
  • 1
  • 3
  • 10

3 Answers3

1

The Ok method takes a byte array as a parameter

So, get a byte array of the contents of the file and try

return ok(s.toByteArray()).as("application/octet-stream");

See this to get a byte array of a file

Community
  • 1
  • 1
Tapan Nallan
  • 1,762
  • 3
  • 17
  • 37
1

You can find a example of chunked response in the documentation:

http://www.playframework.com/documentation/2.1.1/JavaStream

You can send the the csv content while you generate it.

Marco
  • 1,494
  • 13
  • 23
  • I saw this documentation but I am not sure to understand how to do it. I used this for the moment (createCSV method): BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path+filename), "US-ASCII")); And this in the controller: return ok(new java.io.File(path+filename)); Can you give an example of your solution? – fdubrez Jun 05 '13 at 12:02
  • In the method registerOutChannelSomewhere(Chunks.Out out) in the example generate your recordset and instead of create the file use the out object to stream the csv content. – Marco Jun 05 '13 at 16:29
  • It works thanks! One more question, if i have to get data from database, where is the best place to do the request? In the registerOut function ? – fdubrez Jun 20 '13 at 09:50
  • Yes, in the registerOut function. – Marco Jun 20 '13 at 11:42
0

1) Get the output stream from the response

2) Pass this output stream to the createCSV method and write to it directly

You can also zip the results by decorating the output stream with ZipOutputStream.

Note: there is no need to create a temp file.

Lluis Martinez
  • 1,963
  • 8
  • 28
  • 42