# File reading and writing in python :::info This cannot be used with the one compiler for _reasons_ ::: We should use the method open and then close with the path. ```python! file = open("testinput.txt") print(file) ``` output: ![image](https://hackmd.io/_uploads/rJeyydVZbe.png) We have different modes r-> read w -> write a -> append r+ -> read and write. If we don't give the input it will be read by default. If we want to change the way we do it, we can use a string as a second parameter. :::danger Writing is not the same as appending. If you write a file you're overriding what it was before. ::: What if I want to "edit" a file? Usually you read it, you store in a variable and then you write with the appropiate modifications. ```python! file = open("testinput.txt", "a") print(file) ``` ```python! file = open("testinput.txt","a") file.writelines("\nWe're the crystal gems") file.close() ``` For making a new line we need to use special characters. The new line is usually `\n` in text fi ```python! fileData= str(list(range(1,11)))[1:-1] with open ("testfile.txt", "w") as file: file.writelines(fileData) file.close() ``` ```python! fileData= str(list(range(1,11)))[1:-1].replace(", ", "\n") with open ("testfile.txt", "w") as file: file.writelines(fileData) file.close() ``` ```python! myList = list(range(1,11)) string = str(myList)[1:-1] stringWithLines = string.replace(", ", "\n") with open ("testfile.txt", "w") as file: file.writelines(stringWithLines) file.close() ``` #prepare the string myList = list(range(1,10001)) string = str(myList)[1:-1] stringWithLines = string.replace(", ", "\n") #write the file with open("testfile.txt", "w") as file: file.writelines(stringWithLines) file.close() + ```python! file = open("testinput.txt") print(file) for line in file: print(line) splittedLine = line.split(" ") mappedLine = map(float, splittedLine) print(mappedLine) numbers = list(mappedLine) print(numbers) numbers = list(map(int, line.split(" "))) ``` ```python! file open(patata.txt) start = True #Flag variable for line in file: if start: start = False continue if (condition): #dosomething ``` ```python! file open(patata.txt) foundIncludedPlugins = False plugins = [] for line in file: if line == "Included plugins:": foundIncludedPlugins = True if foundIncludedPlugins and line[0] == " ": plugins.append(line) ``` ### Exam exercise the CSV of countries :::info :link: This exercise combines 2D lists that you can look for it here https://hackmd.io/-ylq-DUoTKOS6qGCiq3JRA ::: I have a CSV downloaded from the Canarian Statistics Institute (From the Canary Islands, Spain) with the names of the countries and their coordinates. The full project needs to create a map. The file has this structure (the grey text is the line number, it’s not part of the file but the number that is nonconsecutive is part of the line) ![image](https://hackmd.io/_uploads/H10gmIvIZx.png) The information required is the name of the country and its coordinates (longitude and latitude). A- Construct in Python an algorithm that reads “data.csv” and creates a 2D list called countries with the following structure: [5] ![image](https://hackmd.io/_uploads/Sy_G7IDLbe.png) :::info This is way easier splitting, to check a similar exercise focus in the split part you can go here: https://hackmd.io/y_afcRmLQcysv05xlSqRuQ#Process-data-from-a-line-in-a-csv-file ::: Solution: :::spoiler Implementation 1: ```python! file = open("data.csv") #one mark with the correct opening countries = [] for line in file: #one mark with the correct loop countries.append([]) fields = line.split(",") #1 mark for the split countries[-1].append(fields[1]) #append the second element countries[-1].append(float(fields[3])) #if you miss the casting done with float it's ok countries[-1].append(float(fields[4])) #if you miss the casting done with float it's ok ``` Implementation 2: ```python! file = open("data.csv") #one mark with the correct opening countries = [] row = 0 for line in file: #one mark with the correct loop countries.append([]) fields = line.split(",") #1 mark for the split countries[row].append(fields[1]) #append the second element countries[row].append(float(fields[3])) #if you miss the casting done with float it's ok countries[row].append(float(fields[4])) #if you miss the casting done with float it's ok row = row +1 ``` Implementation 3 (forgot how to split): ```python! file = open("data.csv") #one mark with the correct opening countries = [] for line in file: #one mark with the correct loop countries.append([]) fieldIndex = 0 currentField = "" for char in line: if char != "," and char != "\n": #\n is the special character for "end of the line" I could give the mark if forgot currentField = currentField + char else: if fieldIndex == 1 or fieldIndex == 3 or fieldIndex == 4: countries[fieldIndex] = currentField fieldIndex +=1 fieldIndex = fieldIndex +1 currentField = "" ``` Another implementation without split and "\n" using index while looping through the line. ```python! file = open("data.csv") #one mark with the correct opening countries = [] for line in file: #one mark with the correct loop countries.append([]) fieldIndex = 0 currentField = "" for lineIndex in range(len(line)): #lineIndex can be named li or something shorter in an exam if line[lineIndex] != "," and lineIndex != len(line)-1: currentField = currentField + char else: if fieldIndex == 1 or fieldIndex == 3 or fieldIndex == 4: countries[fieldIndex] = currentField #this implementation doesn't cast the numbers to float fieldIndex +=1 fieldIndex = fieldIndex +1 currentField = "" ``` Another inplementation with no split: ```python! file = open("data.csv") #one mark with the correct opening countries = [] for line in file: #one mark with the correct loop countries.append([ line[line.find(",")+1:line.find(",PAISES")], line[line.find(",PAISES,")+8:line.rfind(",")], line[line.rfind(","):] ]) ``` ::: This exercise continues validating the 2D list here https://hackmd.io/RCQ32fpjS-up6rYC74jPoQ#Validating-country-data