# Programmering 2: Filer ### Inledning Vad händer med alla variabler vi har skapat när programmet stängs av? Jo, de försvinner. Ofta vill vi kunna spara data mellan programkörningar, till exempel för att spara ändringar vi har gjort eller hur långt en spelare har kommit i spel. För att kunna göra det behöver vi kunna skriva och läsa till filer. ### Sökvägar Vi kan ange var en fil som vi vill skriva till eller läsa ligger genom en *sökväg*. Sökvägen är en address på datorn som förklarar var filen ligger. Det finns två typer av sökvägar: * **Absolut sökväg** utgår från "roten" på datorn, och börjar oftast med en bokstav som syftar på en hårddisk. På Windows datorer används oftast C för hårdisken där operativsystemet är installerat. Till exempel: `C:\Users\johan.ronnas\Documents` * **Relativ sökväg** utgår från där programmet körs. När vi skapar program i Visual Studio hamnar själva programmet (.exe-filen) i projektmappen under `bin/Debug/net7.0` eller liknande. En relativ sökväg börjar med ett namn på en mapp eller fil, utan någon bokstav eller inledande snedstreck. Till exempel `minmapp\minfil.txt` syftar på en fil som ligger i projektmappen under `bin/Debug/net7.0\minmapp\minfil.txt`. ### Skriva till fil För att skriva data till en fil med hjälp av C# finns en metod som heter [`File.WriteAllText(string path, string contents)`](https://learn.microsoft.com/en-us/dotnet/api/system.io.file.writealltext?view=net-9.0#system-io-file-writealltext(system-string-system-string)). Den tar in två argument, båda av typen string. Första argumentet är sökvägen till filen, andra argumenten är den text vi vill skriva till filen. *Exempel:* ```csharp string path = "D:\\LBS\\minmapp\\fil.txt"; string content = "Hejhej! Här är en text som jag vill spara!"; File.WriteAllText(path, content); ``` När vi kör koden skapas en fil med namn `fil.txt` i en mapp `minmapp` innuti mappen `LBS` som ligger på en disk med bokstaven `D`. ![image](https://hackmd.io/_uploads/SkbZjHWjle.png) Om man öppnar filen syns texten: ![image](https://hackmd.io/_uploads/By9SiB-sll.png) ### Läsa från fil För att läsa från en befintlig fil finns en metod `File.ReadAllText(string path)`. Den här metoden tar bara ett argument `path` som är sökvägen till filen vi vill läsa. Metoden *returnerar* en string som innehåller all text som finns i filen. *Exempel* ```csharp string path = "D:\\LBS\\minmapp\\fil.txt"; string fileText = File.ReadAllText(path); //Nu innehåller fileText all text som finns i filen //och vi kan till exempel skriva ut den till konsolen Console.WriteLine(fileText); ``` Om vi alltså läser samma fil som vi skrev till i förra exemplet kommer `fileText`-variabeln innehålla texten `Hejhej! Här är en text som jag vill spara!`, och det skrivs ut till konsolen. ### Läsa och skriva rader Ofta vill vi inte läsa in hela innehållet i en fil i en enda string-variabel eftersom det blir ganska knöligt att jobba med. Ett bättre alternativ är att läsa in varje rad för sig och spara resultatet i en array av strängar. För det finns metoden `File.ReadAllLines(string paht)` Den tar samma argument som `File.ReadAllText(string path)`, dvs sökvägen till filen, men returnerar en array av string istället för bara en string. *Exempel* ```csharp string path = "D:\\LBS\\minmapp\\fil.txt"; string[] lines = File.ReadAllLines(path); // Nu innehåller lines alla rader som finns i filen. // Varje element i arrayen motsvarar en rad i filen //Skriver ut fjärde raden (index 3) till konsolen Console.WriteLine(lines[3]); ``` Om vi kör koden med en fil som innehåller följande text kommer det som står på fjärde raden (*"Det här är rad 4"*) skrivas ut till konsolen. ``` Det här är rad 1 Det här är rad 2 Det här är rad 3 Det här är rad 4 ``` Vi kan på motsvarande sätt skriva flera rader till en fil med metoden `File.WriteAllLines(string path, string[] contents)`. Den tar in två argument: första är fortfarande sökvägen till filen, andra är en *array* av strings. Den skriver varje element i arrayen på en egen rad i filen. *Exempel:* ```csharp string path = "D:\\LBS\\minmapp\\fil.txt"; string[] text = new string[3]; text[0] = "Hejhej"; text[1] = "Jag heter Johan"; text[2] = "Jag gillar programmering!"; File.WriteAllLines(path, text); ``` Efter att vi kör koden kommer filen se ut så här: ![image](https://hackmd.io/_uploads/SJ0KxI-oxe.png) ### Fler saker att tänka på! #### Append vs Write Varje gång vi anropar `File.WriteAllText` eller `File.WriteAllLines` skrivs filen över. Det innebär att allt det gamla i filen tas bort och byts ut mot det nya. Ibland är det vad vi vill ska hända, men ibland inte. Om vi istället för att byta ut vill lägga till text i en fil kan vi använda metoderna `File.AppendAllText` och `File.AppendAllLines`. De tar samma argument som motsvarande *write*-metoder, men lägger till texten i slutet av filen. #### Vad händer om filen inte finns? Både *write*-metoderna och *append*-metoderna skapar en ny fil om filen inte redan existerar. Däremot skapar den inga mappar om inte de existerar. Vi kan kolla om en mapp existerar med `Directory.Exists(string path)` som tar in en sökväg och returnerar en bool (sant eller falskt) beroende på om mappen finns. Vi kan också skapar mappar med `Directory.CreateDirectory(string path)`. När vi läser filer måste filen självklart existera för att vi ska kunna läsa den. Vi kan kolla om en fil finns med `File.Exists(string path)`.