# String-Kodierung und -Ausgabe

import sys
import io

text = '123äöüß €'

# einen String UTF8-kodiert auf die Standardausgabe schreiben; Dateiumlenkung
# ist kein Problem
print(text)

# Ausgabe in eine UTF8-kodierte Datei (Standard)
with open('utf8_file', 'w') as f:
    f.write(text + '\n')
    print(text, file=f)

# Ausgabe in eine Latin1-kodierte Datei
#
# € existiert bei Latin 1 nicht:
#   UnicodeEncodeError: 'latin-1' codec can't encode character '\u20ac' in position 8: ordinal not in range(256)
#
# mit 'replace' werden ungültige Zeichen durch ? ersetzt
with open('latin1_file', 'w', encoding='latin1', errors='replace') as f:
    f.write(text + '\n')

# Binär-Ausgabe (Bytes statt String)
with open('latin1_file', 'ab') as f:
    # String explizit mit encode() kodieren
    f.write((text + '\n').encode('latin1', 'replace'))
    # alternativ über bytes()
    f.write(bytes('ä€Ü\n', encoding='latin1', errors='replace'))
    # oder als Bytes-Literal
    f.write(b'***\n')

# alternativ: Nutzung von io.FileIO
with io.FileIO('latin1_file', 'a') as f:
    f.write(b'===')

# Bytes-Objekte sind unverändliche Sequenzen von Integers des Intervalls [0, 255]
for i in b'AB C': print(i)

# Kodierung für Standard-Ausgabe festlegen
#
# extern über die Umgebungsvariable PYTHONIOENCODING möglich:
#
#   PYTHONIOENCODING=utf-8 python3 somescript.py
#
# im Python-Code:
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='latin1', errors='replace', buffering=1)
print(text)
sys.stdout.write(text + '\n')
sys.stdout.buffer.write((text + '\n').encode('latin1', 'replace'))
sys.stdout.buffer.flush()

# Byte-String von der Standard-Eingabe lesen und auf die Standard-Ausgabe
# ausgeben
data = sys.stdin.buffer.read()
print(type(data), file=sys.stderr) # <class 'bytes'>
sys.stdout.buffer.write(data[:100])  # maximal die ersten 100 Bytes ausgeben
