← Python/Bestanden en I/O
Les 6 van 8
MODULE 11 · 06◷ 30 min

Mappen doorzoeken en resultaten voorspelbaar ordenen

Na deze les kun je
  • Gesorteerde relatieve bestandslijststrings met / teruggeven
  • Ontbrekende uitvoerouders maken met behoud van bestaande mapinhoud

Je hebt losse exportbestanden in een map en wilt iedere dag dezelfde overzichtelijke lijst maken. Een bestandsnaam kan ook twee keer voorkomen, eenmaal bovenin en eenmaal in een submap. Je programma moet daarom kiezen waar het zoekt, welke resultaten tellen en hoe het die presenteert.

Directe inhoud of een hele boom

Path(folder).iterdir() levert de directe kinderen van een map. Dat kunnen bestanden én mappen zijn. Met is_file() selecteer je de bestanden; een map met de naam notities.txt blijft immers een map.

De volgorde van een mapiteratie is niet de sorteervolgorde van een woordenboek. Vertrouw voor een herhaalbaar rapport niet op de volgorde waarin bestanden zijn gemaakt of toevallig worden teruggegeven. Gebruik sorted op de namen die je uiteindelijk wilt tonen.

Sorteren is een bewuste stap
z.txt
laatste
a.txt
eerste
toon.py
from pathlib import Path

Path("map.txt").mkdir()
files = [path.name for path in Path(".").glob("*.txt") if path.is_file()]
print(sorted(files))
print(Path("map.txt").is_dir())
Verwachte uitvoer
['a.txt', 'z.txt']
True

Het patroon *.txt zegt iets over de naam, niet over het soort resultaat. Daarom staat ook na glob nog een is_file-controle. In deze les werken we met gewone bestanden en mappen, zonder symbolische links.

Een patroon is geen zoekopdracht naar inhoud

glob("*.txt") zoekt hier één niveau diep naar passende namen. Het leest niet wat er in die bestanden staat. In de hoofdlettergevoelige Linux- en browseromgeving van deze les spreken we af dat .txt kleine letters heeft; UP.TXT doet niet mee aan die selectie.

rglob("*.txt") doorzoekt ook submappen. Een lege map geeft geen bestandsresultaten en een dieper bestand kan meerdere padonderdelen hebben. Ook hier sorteer je de uiteindelijke lijst expliciet, in plaats van de mapboom als al geordend te beschouwen.

Relatieve paden blijven onderscheidbaar
data/a.txt
a
data/sub/a.txt
b
zoek.py
from pathlib import Path

root = Path("data")
found = sorted(path.relative_to(root).as_posix()
               for path in root.rglob("*.txt") if path.is_file())
print(found)
Path("resultaat/dag").mkdir(parents=True, exist_ok=True)
Path("resultaat/dag").mkdir(parents=True, exist_ok=True)
print(Path("resultaat/dag").is_dir())
Verwachte uitvoer
['a.txt', 'sub/a.txt']
True

Alleen de naam is soms te weinig

De twee gevonden bestanden heten allebei a.txt. Met alleen path.name kun je niet meer zien welk bestand uit sub komt. path.relative_to(root) bewaart het pad vanaf de gekozen zoekmap, zonder de tijdelijke bovenliggende map mee te nemen.

Met as_posix() maken we voor deze resultaatlijst een string met schuine strepen. Daardoor heeft de presentatie één afgesproken schrijfwijze. Het is geen controle of willekeurige invoerpaden veilig zijn; deze les doorzoekt alleen de eigen opgegeven lesmap.

Een uitvoermap voorbereiden

Voor resultaat/dag kunnen de ouders nog ontbreken. mkdir(parents=True, exist_ok=True) maakt die zo nodig en accepteert dat de bedoelde map al bestaat. Bestaande bestanden in die map blijven staan.

Een bestaand bestand op precies die plek is een ander geval. exist_ok verandert het niet in een map en verbergt die botsing niet. Laat de fout door, zodat een rapport geen bestaand bestand weggooit om ruimte te maken.

Veelgemaakte fout

Alle resultaten van glob zomaar als bestanden behandelen gaat mis zodra een map hetzelfde achtervoegsel heeft. En bij alleen name raakt een recursieve lijst zijn herkomst kwijt. Selecteer eerst het juiste soort pad en kies daarna bewust tussen een naam en een relatief pad.

AAN DE SLAG 0/4
1

Directe bestanden

Maak file_names(folder): een alfabetisch gesorteerde lijst namen van directe bestanden, ongeacht achtervoegsel. Neem geen mappen of bestanden uit submappen op.

2

Directe tekstbestanden

Maak text_names(folder): alleen directe bestanden waarvan de naam op .txt eindigt, met kleine letters en gesorteerd. Een map die op .txt eindigt telt niet.

3

Recursieve relatieve paden

Maak text_paths(folder): zoek .txt-bestanden ook in alle submappen en geef gesorteerde relatieve padstrings met / terug. Bewaar het onderscheid tussen gelijke bestandsnamen.

4

Uitvoermap voorbereiden

Maak ensure_folder(folder): maak de map en ontbrekende ouders, accepteer bestaande mappen en behoud hun inhoud. Laat FileExistsError door als op de doelplek een bestand staat. Geef None.

Geef bij de eerste drie functies een nieuwe, gesorteerde lijst strings terug. Verander niets aan de doorzochte boom. Bij het maken van een uitvoermap behoud je bestaande inhoud en geef je None terug.

Onthouden

  • Iterdir geeft directe kinderen; rglob zoekt ook in submappen.
  • Patronen kiezen namen, terwijl is_file bestanden onderscheidt.
  • Een relatief pad bewaart herkomst; sorteren maakt de presentatie voorspelbaar.

Hierna bekijken we bestanden als bytes, zonder tekstdecodering.

folders.py
UitvoerPython
›
›_

Hier komt je resultaat.

Voer je code uit en ontdek
wat je hebt gemaakt.

0/4 stappen
EVEN MEEKIJKEN

Bekijk hoe het kan.

Je mag de oplossing bekijken. Deze poging telt dan niet mee als afgeronde les. Met Reset kun je daarna opnieuw zelf oefenen.