Extra empty rows when serving CSV file
The comments for my question were pretty much the answer, but I'll elaborate here.

The root of the problem was one of the included files had an ending PHP tag.  However, it wasn't in my code and I had no idea where else to look.

I ended up using something similar, to the following code.

watchdog("Module_name", "Check these files: !files", array("!files" =&gt; implode(get_included_files(), ', ')));


This gave me a list of all the files that Drupal had included in order to run my code.  There were about 140 of them.  

The best way to figure out which might have superfluous end tags would be to cycle through each file programmatically, as Luke Redpath suggests on http://www.designerstalk.com/forums/programming/8005-php-finding-occurences-string-file.html.

In my case the file permissions were giving me trouble, so I brute forced it until I found an unrelated (but custom) module that had a bunch of ?&gt; tags.