Project K - Inventariseer een schijf

01 - Projectoverzicht
  • In dit project maak je een Python-script dat een map of externe schijf inventariseert.
  • Het script helpt wanneer je wilt weten welke mappen veel ruimte innemen en welke bestandstypen het meest voorkomen.
  • Je gebruikt een testmap of een kleine externe schijf met meerdere submappen.
  • Het script loopt door de mappen en telt bestanden, extensies en totale bestandsgrootte per map.
  • Het resultaat is een overzicht waarmee je ziet waar grote bestanden of oude mappen staan.
  • Je gebruikt AI om code te laten genereren die alleen leest en geen bestanden wijzigt of verwijdert.
  • Je voert de code uit in VS Code en begint met een kleine testmap voordat je een grotere schijf scant.
  • Als de uitvoer te lang is, verbeter je de prompt met limieten zoals top 10 grootste mappen of alleen bepaalde extensies.
02 - Projectmap en Python-omgeving

Voorkennis: doorloop de voorgaande projecten. Het doel en gebruik van .venv zijn uitgelegd in project A, blok 02. Voor ieder nieuw project maak je een eigen omgeving; hieronder herhaal je die bekende stappen.

  • Maak een eigen projectmap project_k en open die map in VS Code. Maak daarin straks inventaris.py.
  • Deze oefeningen voer je lokaal uit in de terminal van VS Code, omdat ze bestanden op je computer lezen of schrijven. Gebruik hiervoor de Python-installatie uit de basiscursus.
  • Controleer je Python-versie. Werkt python op macOS of Linux niet, gebruik dan python3 voor het aanmaken van de omgeving.
python --version
python -m venv .venv

Activeer de omgeving. In Windows PowerShell:

.venv\Scripts\Activate.ps1

In de Windows-opdrachtprompt (cmd):

.venv\Scripts\activate.bat

Op macOS of Linux:

source .venv/bin/activate

Kies in VS Code via Python: Select Interpreter de interpreter uit .venv. Gebruik vanaf nu de geactiveerde terminal. Je verlaat de omgeving later met deactivate.

Dit project gebruikt alleen de standaardbibliotheek van Python. Extra pakketten installeren is niet nodig.

03 - Testgegevens voorbereiden

Maak invoer met submappen documenten en fotos. Zet in beide enkele oefenbestanden en voeg in documenten nog een map oud toe. Plaats ook één bestand direct in invoer.

We meten de som van bestandslengtes in bytes, niet de werkelijk bezette schijfblokken. Een map krijgt het totaal van alle bestanden in haar hele deelboom. Het CSV-bestand staat buiten de gescande map.

04 - Begrippen en hulpmiddelen vóór de opdracht
  • Mappen doorlopen met os.walk ken je uit C. De scan gebruikt dezelfde aanpak voor foutmeldingen en het overslaan van symbolische links.
  • defaultdict(int) begint nieuwe tellers op nul. defaultdict(lambda: [0, 0]) maakt per extensie een aparte lijst met aantal en bytes.
  • De while-lus loopt via parent naar boven tot de invoermap is bereikt. Zo krijgen bovenliggende mappen ook de grootte van hun submappen.
  • sorted(..., key=lambda item: (-item[1], str(item[0]))) sorteert eerst op grootte aflopend en bij gelijke grootte op pad. [:10] beperkt de lijst tot tien regels. Eén MiB is 1024 ** 2 bytes.
  • os.walk bezoekt de mappenstructuur. Een fout bij het openen van een map komt bij onerror terecht.
  • Ieder bestand telt eenmaal in het totaal en eenmaal bij zijn extensie. Voor mapgroottes telt het mee bij de eigen map én alle bovenliggende mappen tot invoer.
  • Tel mapregels niet bij elkaar op: de inhoud van submappen zit al in hun ouders. Harde links worden als aparte bestandsvermeldingen geteld; dit is geen meting van unieke fysieke opslag.
05 - Een gerichte AI-prompt maken

Geef AI eerst een concrete opdracht. Kopieer bijvoorbeeld deze prompt en vergelijk het antwoord met de voorbeeldcode in het volgende blok:

Maak een alleen-lezen schijfinventarisatie van invoer met os.walk zonder
symbolische links te volgen. Tel bestanden en bytes per extensie en
cumulatieve bytes per map inclusief submappen. Sla symbolische links over.
Meld en tel leesfouten; markeer het overzicht dan als onvolledig. Toon
totale bytes en MiB en de top 10 submappen op grootte. Schrijf alle
mapgroottes naar inventaris.csv naast het script. Verander niets in invoer.

Vraag om uitleg bij onbekende regels en controleer welke bestanden de code leest en schrijft voordat je haar uitvoert. Gebruik de oefengegevens uit dit project.

06 - Een werkende basisversie

Dit is een complete basisversie voor inventaris.py. Neem de code over of vergelijk haar met het antwoord van AI.

from pathlib import Path
from collections import defaultdict
import csv
import os

BASIS = Path(__file__).resolve().parent
INVOER = BASIS / "invoer"

def main():
    if not INVOER.is_dir():
        print(f"Map ontbreekt: {INVOER}")
        return
    map_bytes = defaultdict(int)
    extensies = defaultdict(lambda: [0, 0])
    fouten = []
    aantal = totaal = 0
    def meld_fout(fout):
        fouten.append(str(fout))
        print(f"Overgeslagen: {fout}")
    for mapnaam, mappen, namen in os.walk(INVOER, onerror=meld_fout, followlinks=False):
        map_pad = Path(mapnaam)
        map_bytes[map_pad] += 0
        mappen[:] = sorted(m for m in mappen if not (map_pad / m).is_symlink())
        for naam in sorted(namen):
            pad = map_pad / naam
            try:
                if pad.is_symlink() or not pad.is_file():
                    continue
                grootte = pad.stat().st_size
            except OSError as fout:
                meld_fout(fout)
                continue
            aantal += 1
            totaal += grootte
            extensie = pad.suffix.lower() or "(geen)"
            extensies[extensie][0] += 1
            extensies[extensie][1] += grootte
            ouder = pad.parent
            while True:
                map_bytes[ouder] += grootte
                if ouder == INVOER:
                    break
                ouder = ouder.parent
    print(f"Bestanden: {aantal}; bytes: {totaal}; MiB: {totaal / (1024 ** 2):.2f}")
    print(f"Leesfouten: {len(fouten)}" + ("; overzicht is onvolledig" if fouten else ""))
    print("Top 10 submappen (inclusief hun submappen):")
    submappen = [(p, b) for p, b in map_bytes.items() if p != INVOER]
    for pad, grootte in sorted(submappen, key=lambda item: (-item[1], str(item[0])))[:10]:
        print(f"  {pad.relative_to(INVOER)}: {grootte} bytes")
    for extensie, (telling, grootte) in sorted(extensies.items()):
        print(f"  {extensie}: {telling} bestanden, {grootte} bytes")
    with (BASIS / "inventaris.csv").open("w", newline="", encoding="utf-8") as bestand:
        schrijver = csv.writer(bestand)
        schrijver.writerow(["map", "bytes_inclusief_submappen", "leesfouten_scan"])
        for pad, grootte in sorted(map_bytes.items()):
            schrijver.writerow([str(pad.relative_to(INVOER)), grootte, len(fouten)])

if __name__ == "__main__":
    main()
07 - Het script uitvoeren
  • Sla de volledige code op als inventaris.py in je projectmap. Zet eventuele invoerbestanden op de plek die in blok 03 staat.
  • Open de geïntegreerde terminal in die projectmap en activeer .venv als dat nog niet is gebeurd.
  • Voer het script uit met:
python inventaris.py

Lees eerst de terminaluitvoer en open daarna eventuele uitvoerbestanden. Controleer het resultaat met blok 08 voordat je met eigen gegevens verdergaat.

08 - Het resultaat controleren
  • Het aantal bestanden is gelijk aan wat je zelf in de testmap hebt gezet. De rij . in de CSV geeft het totaal van invoer.
  • De bytes van documenten/oud zitten ook in documenten. Het bestand direct in invoer telt alleen in het algemene totaal.
  • Een lege submap krijgt nul bytes. Voer tweemaal uit: de totalen blijven gelijk omdat de CSV buiten de invoermap staat.
09 - Fouten herkennen en oplossen
  • Een grote schijf lijkt te hangen? Begin met de kleine testmap. Het openen van heel veel bestanden en netwerkpaden kost tijd; stoppen kan met Ctrl+C.
  • Andere grootte dan Finder of Verkenner? Vergelijk de bestandslengtes; bezette blokken, verborgen bestanden en toegangsrechten kunnen een verschil verklaren.
10 - Uitbreiden en afronden

Probeer deze vervolgstap pas als de basis werkt:

Laat AI de tien grootste bestanden in een aparte CSV opslaan en een voortgangsmelding per 1000 bestanden toevoegen. Test eerst op een grotere oefenmap en kies pas daarna bewust een externe schijf.

Bewaar je werkende basisversie en verander één onderdeel tegelijk. Geef AI bij een fout de foutmelding, het relevante stukje code, je testinvoer en de verwachte uitkomst.

Het project is afgerond wanneer de basiscontrole uit blok 08 slaagt en je in eigen woorden kunt uitleggen welke invoer wordt gebruikt, hoe de verwerking werkt en waar de uitvoer terechtkomt.