Che il primo esempio è migliore e preferibile.
<se vuoi comprendere>
Perché? Perché il primo esempio usa dei *Reader che (insieme ai *Writer) sono "orientati" ai caratteri. Mentre *InputStream/*OutputStream sono "orientati" ai byte.
Nel primo esempio f.read() legge caratteri, nel secondo esempio f.read() legge byte. Nel secondo usa s.getBytes() (che tra l'altro usa il charset della piattaforma) per ottenere dei byte dalla stringa. Se il charset è tale per cui vale l'equazione 1 carattere=1 byte, effettivamente non hai differenze. Se il charset fosse es. UTF-16, il secondo esempio sarebbe sballato e inappropriato. Punto.