Create CSV file without saving it into file system

17,142

Solution 1

Assuming that CsvBuilder.writeLine(...) does only accept an instance of java.io.Writer, why not using java.io.StringWriter and java.util.Scanner?

// ...

StringWriter writer = new StringWriter();
CsvBuilder.writeLine(writer, headers);
CsvBuilder.writeLine(writer, values);
writer.flush();
    
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=test.csv");

Scanner scanner = new Scanner(new StringReader(writer.toString()));
while (scanner.hasNext()) {
   response.getWriter().write(scanner.next() + "\n");
}

// ...

However, I think Andrei Makarevich's answer using response.getWriter() directly is probably the most forward approach. Although, I'm not sure if the line feeds will be added by CsvBuilder since your adding them explicitly!?

Solution 2

You can try to write directly to response:

Writer writer =  response.getWriter();

CsvBuilder.writeLine(writer, headers);
CsvBuilder.writeLine(writer, values);
writer.flush();
writer.close();

response.setContentType("text/csv");
response.setHeader("Content-Disposition","attachment; filename=" + csvFile);

If that can not be used for some reason and temporary files are also not allowed for you, you can try to use this pretty ugly in-memory variant.

List<Integer> output = new LinkedList<>();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new OutputStream() {
    @Override
    public void write(int b) throws IOException {
        output.add(b);
    }
}));
// write all the things via CsvBuilder
final BufferedReader reader = new BufferedReader(new InputStreamReader(new InputStream() {
    @Override
    public int read() throws IOException {
        if (output.size() > 0) {
            return output.remove(0);
        }
        return -1;
    }
}));

Solution 3

You can try, if temporary files are allowed:

File temp = File.createTempFile("test.csv", ".csv");

These files are getting created in the user storage of the system, so like "C:\Users[Username]\AppData" in Windows, or something like that. I don't know the exact path, but that should not be important now.

Check out all the kinds of OutputStreams, that exist in Java, there is more than the FileOutputStream: https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html Check the subclasses.

Share:
17,142
John
Author by

John

Updated on June 05, 2022

Comments

  • John
    John almost 2 years

    I've created a Java program to create a csv file, write data into it and then send its contents to the server.

    Locally, everything works fine. But the problem is that I don't have write access to the server (permission denied problem).

    So, I can't do any chmod 777.

    I'm looking for a way to create a csv file without saving into the file system. Something like write into a flow or a stream. I don't really know how it works. Any help please ?

    This was what I have done so far:

      public void exportAllToCSV(@PathVariable int id,HttpServletResponse response) throws IOException
     String csvFile="test.csv";
     File file = new File("test.csv");
     //some treatments to get datas (headers and values)
    
    
      FileWriter writer = new FileWriter(csvFile);
      CsvBuilder.writeLine(writer, headers);
      CsvBuilder.writeLine(writer, values);
      writer.flush();
      writer.close();
      response.setContentType("text/csv");
      response.setHeader("Content-Disposition", "attachment; filename=" + csvFile);
      final BufferedReader br = new BufferedReader(new FileReader(file));
    
      try {
            String line;
    
            while ((line = br.readLine()) != null) {
                response.getWriter().write(line + "\n");
            }
        } finally {
            br.close();
        }
    
        try {
            file.delete(); // I delete the file
        } catch (Exception e) {
            e.printStackTrace();
        }
    
    • Erwin Bolwidt
      Erwin Bolwidt over 7 years
      Why do you need to create a file? Why don't you write the CSV file directly to response.getWriter()?
    • rajah9
      rajah9 over 7 years
      You can't write the file without saving it. "Save" means you write the file and close it.
    • Amnor
      Amnor over 7 years
      Why don't you read the file in a BufferedReader, put everyline in an ArrayList, and then work on that? you wouldn't write a file, and you would be working in your operating memory. You can't "write" without saving, "write" is a method that, as its name says, writes to disk.
    • John
      John over 7 years
      @Erwin Bolwidt I need to create a file to put data in it.
    • Erwin Bolwidt
      Erwin Bolwidt over 7 years
      @John Why ? You are deleting the file at the end of the request so clearly you don't need to leave it in the file. As I said in my first comment, you should send the CSV file directly to response.getWriter()
    • John
      John about 7 years
      You're right ! I have writen directly in the response. I didn't know it was possible . Many Thanks
  • Thomas
    Thomas over 7 years
    Apache Commons StringBuilderWriter? Be careful within a multi threaded environment.
  • Erwin Bolwidt
    Erwin Bolwidt over 7 years
    +1 only for the first part. The second part is a bad idea and totally broken since it reads the data back in reverse from what was written. You should just use a StringWriter and a StringReader for that.
  • Andrei Makarevich
    Andrei Makarevich over 7 years
    @ErwinBolwidt thank you, fixed the order, and you are right: as I told the second one is bad and ugly
  • John
    John over 7 years
    Almost . I think you 're right I tried to write directly the response but I have only the content of the csv file in my browser. Like a .txt I don't get a csv file. Any idea ?
  • John
    John over 7 years
    Almost good ! I got the csv but one problem : When there is a space in a sentence, the word after space comes in the next line.. Could you please explain scanner.hasNext() part ?
  • Thomas
    Thomas over 7 years
    scanner.hasNext() checks if another line exists and scanner.next() gets that line. Don't know why you get a line feed when there is a space within a sentence.
  • John
    John over 7 years
    It works ! I have tried directly : response.getWriter().write(writer.toString() + "\n"); Thank you
  • John
    John over 7 years
    Thanks it was really helpful !
  • Hanh Nguyen
    Hanh Nguyen over 2 years
    How about the data is List<Map, String>?