Skip to content

Latest commit

 

History

History
266 lines (224 loc) · 10.3 KB

DATEIEN_UND_VERZEICHNISSE.md

File metadata and controls

266 lines (224 loc) · 10.3 KB

Dateien und Verzeichnisse

Wir organisieren unsere Arbeit in Dateien und Verzeichnissen, und wenn Python uns bei dieser Arbeit unterstützen soll, muss der Interpreter Dateien und Verzeichnisse lesen können. Außerdem wollen wir an vielen Stellen unserer Python-Skripts die Ergebnisse von Berechnungen speichern, um später darauf zurückgreifen zu können.

Um zu verstehen, wie Python mit Dateien und Verzeichnissen umgeht, sind einige Bzeichnungen auseinanderzuhalten:

  • Jede Datei hat einen Pfad und einen Dateinamen.
  • Eine Datei hat in der Regel eine Dateiendung (Extension), z.B. .txt, .docx, .jpg usw.
  • Achtung: Windows-Pfade werden in Python mit einem doppelten Backslash geschrieben (z.B. 'c:\\verzeichnis\\nocheinverzeichnis\\datei.txt'), weil der einfache Backslash als Befehlszeichen interpretiert wird (z.B. \n für newline) und deshalb der Backslash im Pfad geschützt werden muss (escaping) - und zwar mit einem Backslash:
    >>> print('\\')
    \
    
    Alternative: Bei einem Raw String muss der Backslash nicht geschützt werden:
    >>> r'C:\verzeichnis'
    'C:\\verzeichnis'
    

Modul os: Dateien und Verzeichnisse

Ein zentrales Modul, das zahlreiche Funktionen für Dateien enthält, ist das Standardmodul os.

Einige wichtige Funktionen

  • Mehrere String lassen sich zu einem Pfad verbinden:
    >>> os.path.join('verz1', 'verz2', 'verz3', 'datei')
    'verz1/verz2/verz3/datei'
    
    Hinweis: Python "weiß", auf welchem Betriebssystem es läuft, und wählt automatisch den richtigen Slash(/ aus MacOS und Linux, \\ auf Windows).
  • os.getcwd() gibt das aktuelle Arbeitsverzeichnis zurück:
    >>> os.getcwd()
    '/Users/scienceuli/Devel/pfll/Basics'
    
    Wenn man einen Dateinamen ohne Pfad angibt, geht Python davon aus, dass sich die Datei im aktuellen Arbeitsverzeichnis befindet.
  • Relative Pfadangaben (. für aktuelles Verzeichnis, .. für Elternverzeichnis) sind möglich. os.path.abspath() gibt den absoluten Pfad zu einem relativen Pfad zurück. mit os.path.isabs() kann man testen, ob ein Pfad ein absoluter Pfad ist:
    >>> os.path.isabs('verzeichnis')
    False
    >>> os.path.isabs('~/verzeichnis')
    False
    >>> os.path.isabs('/~/verzeichnis')
    True
    
  • os.path.dirname() gibt das Verzeichnis eines Pfades zurück:
    >>> os.path.dirname('verzeichnis1/verzeichnis2/datei.txt')
    'verzeichnis1/verzeichnis2' 
    
  • os.path.basename() gibt nur den Dateinamen zurück:
    >>> os.path.basename('verzeichnis1/verzeichnis2/datei.txt')
    'datei.txt'
    
  • os.path.exists() prüft, ob ein Verzeichnis auf dem Computer vorhanden ist. Es nimmt sowohl relative als auch absolute Pfadangaben entgegen und gibt True oder False zurück.
    >>> os.path.exists('/Users/scienceuli/Devel/pfll/Basics')
    True
    >>> os.path.exists('../Basics')
    True
    
    Mit os.path.isdir() und os.path.isfile() kann die Abfrage noch spzifiziert werden.
  • os.path.getsize() ermittelt die Größe einer Datei in Bytes:
    >>> os.path.getsize('README.md')
    9541
    
  • os.listdir() (Achtung: ohne Submodul path) listet alle Dateien und Ordner in einem Verzeichnis auf:
    >>> os.listdir('.')
    ['print_input.py', 'README.md', 'DATEIEN_UND_VERZEICHNISSE.md']
    
  • os.makedirs() legt ein Verzeichnis an:
    >>> os.makedirs('neues_verzeichnis')
    >>> os.listdir('.')
    ['neues_verzeichnis', 'print_input.py', 'README.md',  'DATEIEN_UND_VERZEICHNISSE.md']
    
    Falls die Pfadangabe mehrere Verzeichnisse enthält, werden diese Verzeichnis genauso angelegt.

Übung: Erzeuge eine typische Dateistruktur für ein Projekt (Verzeichnisse für Manuskripte, Grafiken, Organisation etc.).

os.rename(): Dateien umbenennen

Eine häufige Aufgabe im Redaktionsalltag besteht darin, Dateien umzubenennen. os hält dafür die Methode os.rename() bereit:

>>> os.listdir('.')
['textdatei3.txt', 'textdatei2.txt', 'textdatei.txt', 'print_input.py', 'README.md', 'DATEIEN_UND_VERZEICHNISSE.md']
>>> os.rename('textdatei2.txt', 'umbenannte_Datei.txt')
>>> os.listdir('.')
['textdatei3.txt', 'textdatei.txt', 'umbenannte_Datei.txt', 'print_input.py', 'README.md', 'DATEIEN_UND_VERZEICHNISSE.md']

Nun wird man kein Programm bemühen, um eine einzelne Datei umzubennen. Eher schon, um alle Dateien in einem oder mehreren Verzeichnissen umzubenennen.

Das folgende Skript geht die Dateien in einem Verzeichnis durch und ersetzt mittels der Methode replace(alter String, neuer String) den Bindestrich durch einen Underscore.

# umbenennen.py

'''
liest Dateien aus einem Verzeichnis ein und führt 
eine Umbennung mit replace() durch
'''

import os

pfad = 'Dateien_zum_umbenennen'

datei_liste = os.listdir(pfad)

print('Dateien zum umbenennen:')
print(datei_liste)

for datei in datei_liste:
    os.rename(os.path.join(pfad, datei), os.path.join(pfad, datei.replace('-', '_')))

umbenannt_liste = os.listdir(pfad)
print('Umbenannte Dateien:')
print(umbenannt_liste)

Ausführen des Skripts:

$ python umbenennen.py 
Dateien zum umbenennen:
['datei-9', 'datei-7', 'datei-6', 'datei-1', 'datei-8', 'datei-27', 'datei-18', 'datei-20', 'datei-16', 'datei-29', 'datei-11', 'datei-10', 'datei-17', 'datei-28', 'datei-21', 'datei-26', 'datei-19', 'datei-4', 'datei-3', 'datei-2', 'datei-5', 'datei-23', 'datei-24', 'datei-12', 'datei-15', 'datei-14', 'datei-13', 'datei-25', 'datei-22', 'datei-30']
Umbenannte Dateien:
['datei_30', 'datei_6', 'datei_1', 'datei_8', 'datei_9', 'datei_7', 'datei_13', 'datei_14', 'datei_22', 'datei_25', 'datei_24', 'datei_23', 'datei_15', 'datei_12', 'datei_2', 'datei_5', 'datei_4', 'datei_3', 'datei_17', 'datei_28', 'datei_10', 'datei_26', 'datei_19', 'datei_21', 'datei_20', 'datei_27', 'datei_18', 'datei_11', 'datei_16', 'datei_29']

os.walk()

Mit der Methode os.walk() (genauer: Generator) kann man rekursiv durch ein Verzeichnis "gehen". os.walk(startdir) erzeugt ein Tuple aus startdir, allen Verzeichnissen in startdir und allen Dateien in startdir.

Beispiel:

Das folgende Skript geht durch alle Verzeichnisse und Dateien in path und filtert die eps-Dateien heraus:

# alle_bilder.py

import os
import glob
import fnmatch
import pathlib

path = "/Users/scienceuli/Projekte/DBBay/Bayern8/Verlag_an"

# Variante 1: klassisch
for root, dirs, files in os.walk(path):
    for file in files:
        if file.endswith('.eps'):
            print(file)


# Variante 2: fnmatch
for root, dirs, files in os.walk(path):
    for file in fnmatch.filter(files, '*.eps'):
        # print(file)
        pass

# Variante 3: pathlib.Path (ab Python 3.5)
for file in pathlib.Path(path).rglob('*.eps'):
    # print(os.path.basename(file))
    pass

Für das Herausfischen der eps-Dateien gibt es mehrere Verfahren (siehe Varianten).

Dateien öffnen

Zwei Dateitypen müssen unterschieden werden: Text-Dateien und Binary-Dateien. Erstere enthalten nur Text, Letztere sind alles andere. Mit beiden Dateitypen kann Python umgehen.

Textdateien öffnen, lesen und beschreiben

Mit open() werden in Python Dateien geöffnet. Zusätzlich wird die Methode angegeben, was mit der Datei passieren soll:

  • Wird sie gelesen (read)? Dann open('textdatei.txt', 'r').
  • Wird eine neue Datei angelegt, in die geschrieben (write) werden soll? Dann open('textdatei.txt', 'w').
  • Oder soll in eine bereits vorhandene Datei geschrieben werden (append)? Dann open('textdatei.txt', 'a').

Die Funktion open() öffnet die Datei nur und legt die Methode fest, der eigentliche Lese- oder Schreibvorgang folgt dann. Die geöffnete Datei weist man in der Regel einer Variablen zu, die auf die geöffnete Datei zeigt:

f = open('datei.txt', 'r')

Beispiel:

Die Datei textdatei.txt hat zweu Zeilen:

Dies ist die erste Zeile.
Dies ist die zweite Zeile.

Die Methode read() liest die Datei in einen String ein:

>>> f = open('datei.txt', 'r')
>>> content = f.read()
'Dies ist die erste Zeile.\nDies ist die zweite Zeile.\n'

Beachte: Der String content enthält auch den Zeilenumbruch \n - textdatei.txt ist ja eine zweizeilige Datei.

Wenn man die Datei nicht wieder ordentlich schließt, wird zwar keine Fehlermeldung ausgegeben, trotzdem sollte man das immer machen:

>>> f.close()

Verwendet man statt read() die Methode readlines(), wird die Datei zeilenweise in eine Liste eingelesen:

>>> f = open('textdatei.txt', 'r')
>>> content = f.readlines()
>>> content
['Dies ist die erste Zeile.\n', 'Dies ist die zweite Zeile.\n']
>>> f.close()

Man beachte, dass der Newline-Befehl \n trotzdem noch da ist.

Mit der Methode write() schreibt man in eine Datei:

>>> f = open('textdatei2.txt', 'w')
>>> f.write('Dies ist eine neue Datei!')
25
>>> f.close()

Die Zahl, die von write() zurückgegeben wird, gibt die Zahl der Zeichen an. Sollen zwei Zeilen, die man in eine Datei schreibt, dort auch zwei Zeilen sein, muss man \n mit ausgeben:

>>> f = open('textdatei3.txt', 'w')
>>> f.write('Dies ist die erste Zeile der neuen Datei!\n')
42
>>> f.write('Dies ist die zweite Zeile der neuen Datei!\n')
42
>>> f.close()

Hinweis: Wenn nichts anderes angegeben ist, legt open() die Datei immer im aktuellen Arbeitsverzeichnis an.

Hinweis: Da man evtl. vor hat, der Datei später noch weitere Zeilen hinzuzufügen, sollte man immer am Ende einer Zeile \n mit ausgeben.

Öffnen mit with

Damit eine Datei automatisch wieder sauber geschlossen wird, sollte man with benutzen:

with open('textdatei.txt') as file:
...     file.read()
... 
'Dies ist die erste Zeile.\nDies ist die zweite Zeile.\n'
>>> file.closed
True

Sollen die Zeilen einer Datei direkt beim Einlesen bearbeitet werden, bietet sich ein for loop an.

Beispiel: Die Datei dateiliste.txt enthält alte und neue Dateinamen, jeweils durch Tab getrennt:

alter_name1 neuer_name1
alter_name2 neuer_name2
alter_name3 neuer_name3

Die Zeilen der Datei sollen am Tab aufgespalten und als Key/Value-Paar an ein Dictionary übergeben werden:

>>> with open('dateiliste.txt') as file:
...     datei_dict = dict(line.strip().split('\t') for line in file)
... 
>>> datei_dict
{'alter_name1': 'neuer_name1', 'alter_name2': 'neuer_name2', 'alter_name3': 'neuer_name3'}

Mit diesem Dictionary könnte man zum Beispiel Dateien umbenennen:

>>> import os
>>> for k, v in datei_dict.items():
...     os.rename(k,v)