7.5. File Read

7.5.1. Rationale

  • Works with both relative and absolute path

  • Fails when directory with file cannot be accessed

  • Fails when file cannot be accessed

  • Uses context manager

  • mode parameter to open() function is optional (defaults to mode='rt')

7.5.2. Read From File

  • Always remember to close file

FILE = r'/tmp/myfile.txt'

file = open(FILE)
data = file.read()
file.close()

7.5.3. Read Using Context Manager

  • Context managers use with ... as ...: syntax

  • It closes file automatically upon block exit (dedent)

  • Using context manager is best practice

  • More information in Context Managers

FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    data = file.read()

7.5.4. Read File at Once

  • Note, that whole file must fit into memory

FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    data = file.read()

7.5.5. Read File as List of Lines

  • Note, that whole file must fit into memory

FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    data = file.readlines()
Listing 7.1. Read selected (1-30) lines from file
FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    lines = file.readlines()[1:30]
Listing 7.2. Read selected (1-30) lines from file
FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    for line in file.readlines()[1:30]:
        print(line)
Listing 7.3. Read whole file and split by lines, separate header from content
FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    header, *content = file.readlines()

    for line in content:
        print(line)

7.5.6. Reading File as Generator

  • Use generator to iterate over other lines

  • In those examples, file is a generator

FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    for line in file:
        print(line)
FILE = r'/tmp/myfile.txt'

with open(FILE) as file:
    header = file.readline()

    for line in file:
        print(line)

7.5.7. Assignments

7.5.7.1. Parsing simple CSV file

  • Complexity level: easy

  • Lines of code to write: 15 lines

  • Estimated time of completion: 15 min

  • Solution: solution/file_read.py

English
  1. Download data/iris.csv save as iris.csv

  2. Define:

    • features: List[tuple] - list of measurements (each row is a tuple)

    • labels: List[str] - list of species names

  3. Read file and for each line:

    1. Remove whitespaces

    2. Split line by coma ,

    3. Append measurements to features

    4. Append species name to labels

  4. Print features and labels

Polish
  1. Ściągnij data/iris.csv i zapisz jako iris.csv

  2. Zdefiniuj:

    • features: List[tuple] - lista pomiarów (każdy wiersz to tuple)

    • labels: List[str] - lista nazw gatunków

  3. Zaczytaj plik i dla każdej linii:

    1. Usuń białe znaki

    2. Podziel linię po przecinku ,

    3. Dodaj pomiary do features

    4. Dodaj gatunek do labels

  4. Wyświetl features i labels

The whys and wherefores
  • Reading file

  • Iterating over lines in file

  • String methods

  • Working with nested sequences

7.5.7.2. /etc/hosts - parsing to dict

English
  1. Use data from "Input" section (see below)

  2. Using file.write() save input data from listing below to file hosts-simple.txt

  3. Read file and for each line:

    1. Skip line if contains only whitespaces (str.isspace())

    2. Remove leading and trailing whitespaces

    3. Split line by whitespace

    4. Separate IP address and hosts names

    5. Append IP address and hosts names to result

  4. Merge hostnames for the same IP

  5. Compare result with "Output" section (see below)

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  2. Używając file.write() zapisz dane wejściowe z listingu poniżej do pliku hosts-simple.txt

  3. Zaczytaj plik i dla każdej lini:

    1. Pomiń linię, jeżeli zawiera tylko białe znaki (str.isspace())

    2. Usuń białe znaki na początku i końcu linii

    3. Podziel linię po białych znakach

    4. Odseparuj adres IP i nazwy hostów

    5. Dodaj adres IP i nazwy hostów do result

  4. Scal nazwy hostów dla tego samego IP

  5. Porównaj wyniki z sekcją "Output" (patrz poniżej)

Input
DATA = """
127.0.0.1       localhost
127.0.0.1       astromatt
10.13.37.1      nasa.gov esa.int roscosmos.ru
255.255.255.255 broadcasthost
::1 `            localhost
"""
Output
result: Dict[str, List[str]] = {
    '127.0.0.1': ['localhost', 'astromatt'],
    '10.13.37.1': ['nasa.gov', 'esa.int', 'roscosmos.ru'],
    '255.255.255.255': ['broadcasthost'],
    '::1': ['localhost'],
}
The whys and wherefores
  • Reading file

  • Iterating over lines in file

  • String methods

  • Working with nested sequences

Hint
  • str.isspace()

  • str.split()

7.5.7.3. /etc/hosts - parsing to List[dict]

English
  1. Use data from "Input" section (see below)

  2. Using file.write() save input data from listing below to file hosts-advanced.txt

  3. Read file and for each line:

    1. Skip line if it's empty, is whitespace or starts with comment #

    2. Remove leading and trailing whitespaces

    3. Split line by whitespace

    4. Separate IP address and hosts names

    5. Use one line if to check whether dot . is in the IP address

    6. If is present then protocol is IPv4 otherwise IPv6

    7. Append IP address and hosts names to result

  4. Merge hostnames for the same IP

  5. result must be list of dicts (List[dict])

  6. Compare result with "Output" section (see below)

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  2. Używając file.write() zapisz dane wejściowe z listingu poniżej do pliku hosts-advanced.txt

  3. Przeczytaj plik i dla każdej lini:

    1. Pomiń linię jeżeli jest pusta, jest białym znakiem lub zaczyna się od komentarza #

    2. Usuń białe znaki na początku i końcu linii

    3. Podziel linię po białych znakach

    4. Odseparuj adres IP i nazwy hostów

    5. Wykorzystaj jednolinikowego if do sprawdzenia czy jest kropka . w adresie IP

    6. Jeżeli jest obecna to protokół jest IPv4, w przeciwnym przypadku IPv6

    7. Dodaj adres IP i nazwy hostów do result

  4. Scal nazwy hostów dla tego samego IP

  5. result ma być listą dictów (List[dict])

  6. Porównaj wyniki z sekcją "Output" (patrz poniżej)

Input
DATA = """
##
# ``/etc/hosts`` structure:
#   - IPv4 or IPv6
#   - Hostnames
 ##

127.0.0.1       localhost
127.0.0.1       astromatt
10.13.37.1      nasa.gov esa.int roscosmos.ru
255.255.255.255 broadcasthost
::1             localhost
"""
Output
result: List[Dict[str, Union[str, Set[str]]] = [
    {'ip': '127.0.0.1', 'protocol': 'ipv4', 'hostnames': {'localhost', 'astromatt'}},
    {'ip': '10.13.37.1', 'protocol': 'ipv4', 'hostnames': {'nasa.gov', 'esa.int', 'roscosmos.ru'}},
    {'ip': '255.255.255.255', 'protocol': 'ipv4', 'hostnames': {'broadcasthost'}},
    {'ip': '::1', 'protocol': 'ipv6', 'hostnames': {'localhost'}}
]
The whys and wherefores
  • czytanie i parsowanie pliku

  • nieregularne pliki konfiguracyjne (struktura może się zmieniać)

  • filtrowanie elementów

  • korzystanie z pętli i instrukcji warunkowych

  • parsowanie stringów

  • praca ze ścieżkami w systemie operacyjnym

Hints
  • str.split()

  • str.isspace()

  • value = True if ... else False