Start | filhantering
 

Filhantering



Fil ?

En fil är någon form av data, text eller bild vanligtvis, som du skapat eller laddat hem. Du har säkert någon katalog där du sparat dina bilder eller texter du skrivit. Dessa data ligger som filer på din dator.

För att kunna läsa filen måste du dels i förväg veta hur du skall tolka innehållet. Är det en bild? Det är skillnad på png -bilder och jpg -bilder. Är det en text? Är det löptext eller är det json -formaterat text, kommaseparerad data?

Du måste ha korrekt sökväg till filen. Om filen ligger i samma katalog som ditt python -program, då behöver du bara ange själva filnamnet. Men om din pythonkod ligger i en annan katalog än din fil, då måste du ange en absolut sökväg till din fil.

Absolut sökväg


En absolut sökväg är en fullständig sökväg, från roten på disken. På en windows-maskin kan det se ut såhär:

C:\Users\Viking\Desktop\text.txt

Ett problem här, det är att \ är koden för escape-tecken. Om du sitter på en windows-maskin lägg till ett litet "r" framför sökvägen.

f = open(r"C:\Users\Viking\Desktop\text.txt")

Observera att nedanstående exempel läser filer på webbservern (där python-rummet.se ligger), som är en linux -server. Då används istället / och problemet uppstår inte.

Tänket


Hur ska vi tänka här? Typisk uppgift är att vi skall läsa in en textfil, göra något, skriva ut resultatet.



Rad för rad


Vi använder en exempelfil som ligger på servern för detta ändamål.

Läser en rad i taget ...
f = open('/ex/text.txt') for rad in f: print(rad,end="") f.close()

readline()


Läser en rad. Returnerar ’ ’ vid filslut ...
f = open('/ex/text.txt') while(rad:= f.readline()): print(rad,end="") f.close()

read()


Läser hela filen och returnerar ...
f = open('/ex/text.txt') text = f.read() print(text) f.close()

read(antal_tecken)


Läser 10 tecken och returnerar ’ ’ vid filslut
f = open('/ex/text.txt') text = f.read(10) print(text) f.close()

[ ... ] = readlines()


Läser in alla rader i en lista. Vi kan sedan traversera listan och göra det vi vill göra.
f = open('/ex/text.txt') rader = f.readlines() print(rader) print() for i in range(0,len(rader)): print(rader[i]) f.close()

with open ...


Vi kan öppna en fil med kontextmanagern with. Fördelen är att koden blir kompaktare och vi behöver dessutom inte tänka på att stänga filen med close(). Det sköts automatiskt med with.

Nedan kommer innehålla en lista med filens rader. Notera att vi läser filen med ett generator -uttryck här. Vi kan sedan göra det vi vill göra, med denna lista. Lägg märke till att radslut är med i data från varje rad. Det beror ju på att det finns en radslut i slutet på varje rad i filen.
with open('/ex/text.txt') as f: rader = [rad for rad in f] print(rader)
Som ovan, fast vi har plockat bort radslutet på varje rad, vilket gör det lättare bearbeta datan.
with open('/ex/text.txt') as f: rader = [rad.rstrip() for rad in f] print(rader)

HTML -fil

Ett exempel på html -fil (öppnas i ny flik).

Nu när du vet hur den ser ut i verkligheten, låt oss läsa filen och se hur det ser ut.
f = open('/ex/exempel1.html') text = f.read() print(text) f.close()
Vill vi rensa bort alla html -taggar i texten kan vi göra det såhär.
import re f = open('/ex/exempel1.html') html = f.read() text = re.sub('<.*?>', '', html) print(text) f.close()
För att förstå re.sub och det reguljära uttrycket som filtrerar bort all html -kod, titta i regex labbet (nytt fönster).
f = open('/csv/gistemp.csv') print(f.read()) f.close()
f = open('/json/periodictable.json') print(f.read()) f.close()
f = open('/csv/allcontries.csv', encoding="latin-1") lines = [x.rstrip() for x in f.readlines()] print(lines) f.close()

molekylvikt, tentauppift (ish)


Antag vi har en textfil med atomer och deras massa, på varje rad en atom och massa åtskilld av mellanslag, exempel på fil: /ex/atom_massa.txt (öppnas i nytt fönster). Vi ska nu skriva en funktion som givet en molekyl t.ex. CH4, beräknar dess massa. Vi kan utnyttja att multiplikatorn alltid kommer efter atomen och vi kan anta att multiplikatorn bara är en (1st) siffra 2-9. OBS uppgiften förutsätter att även atomen enbart har en (1 st) bokstav (för en mer avancerad variant som kommer runt detta, se nästa uppgift).

Vi börjar med att läsa in filen och skapar en dictionary så att vi snabbt kan slå upp molekylvikten givet en atom.

För att beräkna en viss molekyls vikt loopar vi över strängen. Om tecknet är en bokstav, då är det en atom, dvs vi kollar upp vikten och lägger vikten i en lista. Om tecknet i strängen är en siffra, så multiplicerar vi senast ditlagda vikt i vår lista med denna multipel. Slutligen summerar vi alla vikter i vår lista och returnerar svaret.
vikt={} with open('/ex/atom_massa.txt') as fil: for rad in fil: atom,massa = rad.split() vikt[atom]=massa def mass(molekyl): molekylvikt=[] for m in molekyl: if(m.isnumeric()): molekylvikt[-1] = molekylvikt[-1] * float(m) else: molekylvikt.append(float(vikt[m])) return(sum(molekylvikt)) print("H2O",mass("H2O"),"g/mol") print("CH4",mass("CH4"),"g/mol") print("H2SO3",mass("H2SO3"),"g/mol")

molekylvikt, mer avancerad lösning


Om även 2-bokstavs atomer samt flersiffriga multipler ska tillåtas (typ alla molekyler), så kan vi splitta molekylen med reguljära uttryck, i detta fall findall(). Tricket vi kör, det är att först gör om molekyl-strängen till en lista, så t.ex. "AlCl3" blir ['Al','C','3'] eller "C5H12O" blir ['C','H','12,'O']. Detta gör vi med reguljära uttryck. På så vis kan vi hantera alla atomer och även stora multipler.
import re vikt={} with open('/ex/atom_massa.txt') as fil: for rad in fil: atom,massa = rad.split() vikt[atom]=massa def mass(molekyl): atomer = re.findall(r'([A-Z][a-z]+|[A-Z]|[0-9]+|\))', molekyl) molekylvikt=[] for m in atomer: if(m.isnumeric()): molekylvikt[-1] = molekylvikt[-1] * float(m) else: molekylvikt.append(float(vikt[m])) return(round(sum(molekylvikt),2)) print("H2O, Vatten",mass("H2O"),"g/mol") print("CH4, Metan",mass("CH4"),"g/mol") print("H2SO3, Svavelsyrlighet",mass("H2SO3"),"g/mol") print("C6H14, Hexan",mass("C6H14"),"g/mol") print("C5H12O, 1-Pentanol",mass("C5H12O"),"g/mol") print("HCl, Saltsyra",mass("HCl"),"g/mol") print("NaCl, Natriumclorid",mass("NaCl"),"g/mol") print("AlCl3, Aluminiumklorid",mass("AlCl3"),"g/mol")
En lösning utan reguljära uttryck kan se ut såhär. Vi splittar molekylen genom att hitta bokstäverna och siffrorna i strängen, och se till att vi får med alla siffror och bokstäver i en lista som vi sedan returnerar.
vikt={} with open('/ex/atom_massa.txt') as fil: for rad in fil: atom,massa = rad.split() vikt[atom]=massa def splitmolekyl(str): lista = [] i = 0 while(i < len(str)): if(str[i].isnumeric()): j = i+1 while(j < len(str) and str[j].isnumeric()): j +=1 lista.append(str[i:j]) i = j-1 elif(str[i].isupper()): j = i+1 while(j < len(str) and str[j].islower()): j +=1 lista.append(str[i:j]) i = j-1 i += 1 return(lista) def mass(molekyl): atomer = splitmolekyl(molekyl) molekylvikt=[] for m in atomer: if(m.isnumeric()): molekylvikt[-1] = molekylvikt[-1] * float(m) else: molekylvikt.append(float(vikt[m])) return(round(sum(molekylvikt),2)) print("H2O, Vatten",mass("H2O"),"g/mol") print("CH4, Metan",mass("CH4"),"g/mol") print("H2SO3, Svavelsyrlighet",mass("H2SO3"),"g/mol") print("C6H14, Hexan",mass("C6H14"),"g/mol") print("C5H12O, 1-Pentanol",mass("C5H12O"),"g/mol") print("HCl, Saltsyra",mass("HCl"),"g/mol") print("NaCl, Natriumclorid",mass("NaCl"),"g/mol") print("AlCl3, Aluminiumklorid",mass("AlCl3"),"g/mol")

Lite frågor


f = open('/ex/text.txt')
text = f.read()
Vad gör f.read() ?
  Läser in ett ord
  Läser in en rad
  Läser in hela filen
f = open('/ex/text.txt')
text = f.read(10)
Vad gör f.read(10) ?
  Läser in 10 ord
  Läser in 10 tecken
  Läser in 10 rader
f = open('/ex/text.txt')
text = f.readlines()
Vad gör f.readlines() ?
  Läser in en rad och skapar en lista av ord
  Läser in hela filen och gör en lista av rader
  Läser in ett ord och gör en lista av tecken
with open('/ex/text.txt') as f:
    text = [rad for rad in f]
Vad gör [rad for rad in f] ?
  Läser in en rad i taget och gör en lista av raden
  Generator som skapar en serie av rader, som blir en lista av rader
  Läser rad för rad och ger ifrån sig texten
17.009973526001 ms