If there is a comprehensive 'streams in free pascal' tutorial somewhere please direct me to the proper RTFM department, I didn't find it myself.FPC streams are Delphi compatible, so you can use Delphi materials as well. Not that there are many of them, since it's not really a big topic. Here's a simple yet to the point explanation: https://www.thoughtco.com/tstream-class-in-delphi-4077896
What I'm doing right now: I want to write procedures/methods that take a TStream (any of them) and read/write text from/to it, be it a TFileStream or TStringStream or whatever (in practice, only those two, but I'm interested in the general case for learning).I suggest creating the TTextReader inside Load implementation instead of as parameter. Normally for this kind of API, you don't want to expose how the loading process is supposed to be done, you just know that you can load something from a given TStream. The same principle applies to Save. Other than that, unless the TStream descendant you expect to work with isn't capable of either Read (e.g. TWriteBufStream) or Write (e.g. TReadBufStream), you shouldn't do any runtime type check. After all, if you want to deal with TStream in general and not any specific descendant of it, just assume it's a TStream. i.e. just call TStream methods and properties, neither of its descendants.
...
Again, it works but feels wrong. I know I could work around the problem altogether, for instance always writing the whole text to a string or TStringList and then dumping it to file if it needs be, or testing 'if mystream is TFileStream then...else...'
Am I correct to assume Free Pascal classes mirror Delphi ones, to the point its docs also apply here?As I said above, yes. Mostly, at least.
Why is there a TTextReader but no TTextWriter?Because it's not as difficult or practical? Line oriented reading requires some cumbersome code to detect newlines (which could be in multiple formats) and return part of the long string until that newline. For writing, however, it's straightforward. Just write something then write a newline. Done. No cumbersome code required.
What is the difference between using TStringReader and instead TStreamReader.Create(TStringStream(...))?The former reads directly from a string, the latter reads from a stream made from a string. The former should be a tad faster.
What is the difference between a TStringStream and a TMemoryStream?TStringStream is a stream made from (ansi)string, while TMemoryStream is made from memory... I mean raw bytes of data in memory, it doesn't know nor care in what format the data is, you are fully responsible for it.
What happens if my text is unicode?Unclear what you ask this in connection to.
I see there is a StreamIO unit which I discovered too late and haven't tried yet. It seems like the way to go, is it?Arguable. As written in the overview (https://www.freepascal.org/docs-html/current/fcl/streamio/index.html), the unit is meant to use compiler built-in Read and Write procedures (that you normally begin Pascal programming with) on streams. Everything else is built upon those two procedures. e.g. if you have an old program that reads from standard input and writes to standard output but you want to easily change the program to read from network stream and write to text file, you can simply AssignStream a TNetworkStream (no, it doesn't exist, just to show you a possibility to Input (or StdIn) and a TFileStream to Output (or StdOut) and what you want is achieved automagically.
If so, how does it handle text which might be utf8? (let's say I don't care all the other encodings beyond ascii and utf8) Or should I use TCharEncStream? The two of them together somehow?Read is incapable of reading types outside of Char, Integer, Real and String. So don't use StreamIO for this purpose.
Also I'm not sure I understand how I'm supposed to use the StreamIO (ok, this will perhaps become clear once I actually try it in code): it seems to me I would declare a 'dummy' file variable, call StreamIO's 'Assign' on it, then read/write the file variable knowing that actually StreamIO will take over and do its thing, is that correct?I see this unit lacks example in its docs though there's a demo (https://svn.freepascal.org/svn/fpc/trunk/packages/fcl-base/examples/demoio.pp) in trunk repo.