# 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:

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)

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]

:::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