Your problem is with not reassigning $Output back to stdout. You could do it by writing your code like so:
fname = FileNameJoin[{HomeDirectory[], "Desktop", "test.txt"}];
Module[{out = $Output},
$Output = OpenWrite[fname, FormatType -> OutputForm];
Write[$Output, "The quick brown fox ..."];
Print[$Output];
Close[$Output];
$Output = out]
The file written out by this code looks like this:
The quick brown fox ...
OutputStream[/Users/oldmg/Desktop/test.txt, 126]
The file is properly closed and no error messages ensue. However, I don't think that's good practice. I much prefer this approach which makes reassignment unnecessary:
Block[{$Output = OpenWrite[fname, FormatType -> OutputForm]},
Write[$Output, "The quick brown fox ..."];
Print[$Output];
Close[$Output]]
Edit
As rcollyer points out in a comment, it is a good idea have some error handling; in particular, the file should be closed even if an abort should occur between the time the file is opened and the time it is closed.
Block[{$Output, rtn},
rtn = OpenWrite[fname, FormatType -> OutputForm];
If[rtn === $Failed,
$Failed,
AbortProtect[
$Output = rtn;
Write[$Output, "The quick brown fox ..."];
Print[$Output];
Close[$Output]]]]
Abortis issued, the stream is not closed. This question has a few strategies for handling that. – rcollyer Aug 13 '13 at 03:00AbortProtect. I'll make an update that does that. – m_goldberg Aug 13 '13 at 03:07BlockStream, but there is some evidence that [Internal`WithLocalSettings](http://mathematica.stackexchange.com/a/1603/52) handles most cases, and I tend to use it almost exclusively, now. Definitely something to keep in ones tool chest. – rcollyer Aug 13 '13 at 03:18