Since $I is a compiler directive, it can only affect code generated by the compiler, and can only affect code that actually compiles.
For two reasons, it cannot affect things like TFileStream . This is a class in Classes.pas, which is a unit that you are not compiling. Any code in it does not depend on the $I directive. In addition, the compiler does not specifically refer to this class. This is just another class.
The $I directive affects the built-in language features that you mentioned. The compiler generates calls to these functions on purpose. It also affects write , writeln and readln . It should also affect BlockRead and BlockWrite .
You can check the source code. Everything that causes SetInOutRes is susceptible to $I This includes functions that open files ( Append , Reset and Rewrite ), as well as anything that accepts a parameter of type file or TextFile ( Flush , BlockRead , BlockWrite , Erase , FilePos , Seek , FileSize , Read , readln , write , writeln , Rename , Eof , SeekEof , Eoln , SeekEol , Truncate , SetLineBreakStyle and CloseFile ). In addition, everything that causes InOutError ( ChDir , ChDir , amd RmDir ).
Noticeably absent from the AssignFile list. This function does not actually perform I / O. It simply sets up a file entry so that Append , Reset and Rewrite know what to do.
I must point out that looking at the source code is just a conclusion. The $I directive determines whether the compiler will insert calls to the __IOTest function in your own code after calling some other functions. This function checks the value of InOutRes , and if it is not equal to zero, a runtime error occurs (which may lead to an exception if SysUtils is included in your program). We cannot check the source code to directly find out which functions are affected by $I (since it is only called in the code generated by the compiler), so we really just look for which functions we install InOutRes on the assumption that they will not worry about it, if they don’t know that the compiler will check it after that.