I'd look at writing a query to produce the comma separated values, taking care to string out any extraneous carriage returns or other funnies that would break the format, especially if you have columns that are free-form text entry and might have all sorts of entries in them. I once saw data for "email_content" that had an example of comma-separated values pasted into it. That was fun.
Your code would end up along the lines of ....
Then either use SQL*Plus to spool the output, using the commands shown in the docs to suppress headings, set a suitable line size, suppress feedback of the number of rows, increase the default arraysize to around 100 perhaps, or use UTL_File to spool it out as a server process.