Pliki

https://docs.python.org/3/library/functions.html#open

WPROWADZENIE

Python jest dobrze przygotowany do bezpośredniej obsługi zarządzania plikami i ich przetwarzania. Zawiera kilka wbudowanych funkcji oraz dodatkowych modułów, które pomagają w zarządzaniu plikami.

Obiekty plików są w Pythonie głównym interfejsem do plików zewnętrznych znajdujących się na komputerze.

Tworzymy obiekt pliku (file object) za pomocą funkcji open(). Po użyciu pliku powinno się go zamknąć za pomocą wbudowanej metody close(), aby zwolnić zasoby systemowe powiązane z otwartym plikiem. Otwarte pliki są automatycznie zamykane na zakończenie przetwarzania skryptu. Po zamknięciu pliku nie można go już przetwarzać.

W Pythonie rozróżnia się pomiędzy plikami tekstowymi, a plikami binarnymi. Zawartość pliku tekstowego może być podzielona na wiersze. Każdy wiersz, ewentualnie oprócz ostatniego, kończy się znakiem końca wiersza (zwykle "\n", newline).

W Pythonie 3 pliki otwarte w trybie tekstowym zwracają zawartość jako string, gdzie bajty są dekodowane do 'code points' z użyciem ustawionego kodowania (encoding).

Pliki inne niż tekstowe to pliki binarne, które powinny być przetwarzane przez aplikacje znające ich strukturę. Takie pliki zwracają ciąg bajtów bez żadnego dekodowania. Nie określa się kodowania dla operacji w trybie binarnym.


afile = open(file_name, mode='r' [, buffering])   # Py2
afile = open(file_name, mode='r', buffering=-1, encoding=None, errors=None,
    newline=None, closefd=True, opener=None)   # Py3
afile = open(file_name, 'r', encoding='utf-8')   # Py3, typowe wywołanie
# file_name (string): nazwa pliku;
# mode (string):
# "r" (czytanie),
# "w" (pisanie; kasowanie poprzedniej zawartości; utworzy plik, gdy nie istniał),
# "a" (dopisywanie; poprzednia zawartość pozostaje), 
# "x" (exclusive creation, failing if the file already exists),
# "r+" (czytanie i pisanie; poprzednia zawartość pozostaje),
# "w+" (czytanie i pisanie; kasowanie poprzedniej zawartości),
# "a+" (czytanie i pisanie; poprzednia zawartość pozostaje),
# "t" (dodatek do poprzednich, tryb tekstowy, domyślny w Py3),
# "b" (dodatek do poprzednich, tryb binarny),
# "U" (dodatek do poprzednich, uniwersalny translator nowych wierszy, deprecated).
# encoding : zwykle "utf-8" lub domyślne, używa się w text mode (Py3);
help(open)
dir(afile)     # spis metod
afile.close()   # otwarty plik należy zamknąć

Odczytywanie danych z otwartego pliku tekstowego (mode "r").


S = infile.read()      # przeczytanie całego pliku
S = infile.read(5)      # przeczytanie 5 znaków/bajtów w Py2
S = infile.read(5)      # przeczytanie 5 code points w Py3
# Przy pustym pliku S będzie równe "".
# Pusta linia to napis równy "\n".

S = infile.readline()
# Czyta jedną linię razem ze znakiem '\n'.

L = infile.readlines()
# Czyta wszystkie linie i przechowuje je jako listę stringów z '\n' na końcu.

L = infile.readlines(50)
# Czyta 50 bajtów w Py2 (code points w Py3) lub więcej, aby była pełna linia!
# To jest przydatne przy czytaniu dużych plików, aby nie wczytywać
# całości do pamięci.
# Taką listę stringów można zapisać do pliku przez outfile.writelines(L).

Jeżeli plik został otwarty w trybie binarnym (mode "rb"), to funkcja read() zwróci obiekt typu 'bytes'.

Zapisywanie danych do otwartego pliku tekstowego (mode "w").


number = 52   # różne typy danych
x = 1.2345
word = "abc"

outfile.write("jeden\n")            # metoda zwraca None
outfile.write(str(number) + "\n")     # tu trzeba dodawać '\n'
outfile.write(str(x) + "\n")
outfile.write(word + "\n")

outfile.write("%d\n" % number)      # zapis z procentem
outfile.write("%f\n" % x)
outfile.write("%s\n" % word)

# Tego sposobu lepiej unikać, chyba trudniej przerobić na funkcję (Py2).
print >> outfile, number   # drukuje tak jak na ekran, jest '\n'
print >> outfile, x
print >> outfile, word

print >> outfile, "%s\t%s\t%s" % ("a1","a2","a3")
outfile.write("%s\t%s\t%s\n" % ("a1","a2","a3"))   # tutaj trzeba dać '\n'
outfile.write("%s\n" % "\t".join(["a1","a2","a3"]))   # sklejam przed wypisaniem
outfile.write("{}\t{}\t{}\n".format("a1","a2","a3"))   # zalecane

outfile.flush()
# Flush the internal I/O buffer.
# Dopiero po flush() lub close() mamy pewność, że dane są zapisane na dysku,
# a nie czekają w buforze na zapisanie.

Różne operacje na pliku (mode "r+").


afile.write("0123456789abcdefgh")

# afile.seek(offset[, whence])
# Funkcja ustawia nową pozycję w pliku i zwraca pozycję po zmianie.
# offset - ku końcowi (dodatni) lub początkowi (ujemny, tylko Py2)
# whence=0 (domyślnie), offset > 0, bo od początku pliku
# whence=1, offset dodatni lub ujemny, bo liczymy od bieżącego położenia w pliku
# whence=2, offset < 0, bo od końca pliku

afile.seek(5)                 # idź do 6-tego bajtu
N = afile.tell()              # zwraca aktualną pozycję w pliku (integer)
S = afile.read(1)             # czytaj 1 bajt w Py2 (czytaj 1 code point w Py3)
afile.seek(-3,2)              # idź do 3-go bajtu od końca (tylko Py2)

PRZYKŁAD

Mamy napisać funkcję wykonującą kopiowanie pliku (Py2).


def copy_file(infile_name, outfile_name):
    infile = open(infile_name, "r")
    outfile = open(outfile_name, "w")
    while True:
        text = infile.read(50)      # ograniczenie
        if text == "":
            break           # przerywa pętlę na końcu pliku
        outfile.write(text)
    infile.close()
    outfile.close()

Powyższa funkcja działa dla wszystkich rodzajów plików. Dla plików tekstowych można uprościć kod przez zastosowanie iteracji po pliku.


def copy_file(infile_name, outfile_name):
    """Kopiowanie plików."""
    infile = open(infile_name, "r")
    outfile = open(outfile_name, "w")
    for line in infile:
        outfile.write(line)
    infile.close()
    outfile.close()

def print_file(file_name):
    """Wypisywanie zawartości pliku na stdout."""
    afile = open(file_name, "r")
    for line in afile:
        #print line,   # line zawiera '\n' (Py2)
        print(line, end="")   # line zawiera '\n' (Py3)
    afile.close()

UŻYCIE MENEDŻERA KONTEKSTU (ZALECANE)


with open('book.txt', 'r') as infile:   # infile zostanie zawsze zamknięte
    text = infile.read()
    # for line in infile: ...

with open('results.txt', 'w') as outfile:   # outfile zostanie zawsze zamknięte
    outfile.write(text)