Программирование для дата-журналистики

Конспект лекции о работе с файлами и путями к ним

Мы будем работать с функциями для работы с операционной системой, для этого нам нужно импортировать модуль os.

In [1]:
import os

Функция getcwd() (get current work directory) — возвращает абсолютный путь к текущей рабочей директории/каталогу/папке. Это далеко не обязательно та директория в которой находится запущенный .ipynb файл. В зависимости от операционной системы путь может выглядеть по-разному:

"/disk/user/dir" — под Mac/Linux
"D:\\user\\dir" — под Windows (в целом, современные версии понимают написание не через обратный слеш)
In [ ]:
os.getcwd()

Так, например, если в текущем рабочем каталоге будет находиться файл "myfile.txt", то мы сможем открыть его указав лишь его имя.
Но абсолютный путь к файлу будет выглядеть как:

"/disk/user/dir/myfile.txt"
или
"D:\\disk\user\dir\myfile.txt"
In [3]:
with open("myfile.txt") as f:
    print(f.read())
Hello!
This is file with text.

Обратите внимание, что если вы хотите вручную прописать путь к файлу, а не только его имя, чтобы использовать в строке символ обратного слеша вам нужно написать его дважды "\\", т.к. сам по себе знак "\" имеет особый смысл (например, используется для передачи специальных символов типа \n)

In [4]:
print("a\\b")
a\b

Задача

In [ ]:
# Создайте любой файл в текущем рабочем каталоге
# Откройте его, используя абсолютный путь, как в примере внизу
In [6]:
with open("/Users/teacher/myfile.txt") as f:
    print(f.read())
Hello!
This is file with text.

In [7]:
with open("/Users/teacher/My Nice Folder/myfile.txt") as f:
    print(f.read())
File in folder «My Nice Folder».

In [8]:
with open("My Nice Folder/myfile.txt") as f:
    print(f.read())
File in folder «My Nice Folder».

Текущий рабочий каталог можно поменять, используя функцию os.chdir(). Ваш .ipynb файл при этом останется на прежнем месте, измениться лишь точка отсчета для доступа к файлам.

In [13]:
os.chdir('/Users/teacher')
In [14]:
os.chdir("My Nice Folder")
In [15]:
os.getcwd()
Out[15]:
'/Users/teacher/My Nice Folder'

Будьте внимательны, при смене рабочего каталога вы не сможете открывать только по имени файлы, которые лежали в прежнем рабочем каталоге.

In [16]:
with open("myfile.txt") as f:
    print(f.read())
File in folder «My Nice Folder».

In [17]:
with open("/Users/teacher/myfile.txt") as f:
    print(f.read())
Hello!
This is file with text.

Так же как и с файлами, если вам необходимо обратиться к каталогу, который лежит в текущем рабочем каталоге, вам достаточно просто написать его имя. Если же вы хотите обратиться к каталогу, в котором находится ваш текущий рабочий каталог, досаточно написать "..".

Например, наша файловая система выглядит следующим образом:

disk/user/dir0/dir1/dir2

Текущий рабочий каталог — dir1, нам необходимо обратиться к каталогу dir2, тогда достаточно написать "dir2/". Если мы хотим попасть в каталог dir0, нужно написать "../"

In [18]:
with open("../myfile.txt") as f:
    print(f.read())
Hello!
This is file with text.

Путь, который строится относительно текущего рабочего каталога, называется относительным путём.

Путь "./" (одна точка) — это способ указать текущий рабочий каталог в виде строки.

In [20]:
with open("./myfile.txt") as f:
    print(f.read())
File in folder «My Nice Folder».

In [21]:
os.chdir("/Users/teacher")

Метод os.listdir() возвращает список всех объектов (и файлов и каталогов), которые содердатся в директории. В скобках можно указать путь к директории (в виде строки, например, os.listdir("disk/user/dir0/dir1/dir2")) список объектов которой необходимо получить, по умолчанию функция возвращает список объектов текущего рабочего каталога.

In [25]:
os.listdir()
Out[25]:
['.adobe',
 '.anaconda',
 '.atom',
 '.bash_history',
 '.bash_profile',
 '.bash_sessions',
 '.cache',
 '.CFUserTextEncoding',
 '.conda',
 '.condarc',
 '.cups',
 '.DS_Store',
 '.gitconfig',
 '.ipynb_checkpoints',
 '.ipython',
 '.jupyter',
 '.local',
 '.oracle_jre_usage',
 '.spss',
 '.ssh',
 '.Trash',
 '.viminfo',
 'anaconda3',
 'Applications',
 'Desktop',
 'Documents',
 'Downloads',
 'electors.csv',
 'large_states.txt',
 'Library',
 'Movies',
 'Music',
 'My Nice Folder',
 'myfile.txt',
 'newfile.txt',
 'Pictures',
 'Public',
 'results.csv',
 'test',
 'test_work_xjz.ipynb',
 'Untitled.ipynb',
 'Untitled1.ipynb',
 'Untitled2.ipynb',
 'Untitled3.ipynb',
 'Untitled4.ipynb']
In [26]:
os.listdir("My Nice Folder/")
Out[26]:
['myfile.txt']

Файл в каталоге не всегда может иметь в конце названия привычное расширение в виде несколькоих знаков после точки (.txt/.csv). Чтобы определить является ли объект каталога файлом, а не каталогом, существует функция os.path.isfile(), которая на вход принимает путь к файлу в виде строки.

In [27]:
os.path.isfile("results.csv")
Out[27]:
True
In [30]:
os.path.isfile("My Nice Folder")
Out[30]:
False

Соответственно с помощью функции os.path.isdir можно проверить является ли объект директорией.

In [31]:
os.path.isdir("My Nice Folder")
Out[31]:
True
In [34]:
# Задача: вывести на экран все файлы в текущем каталоге (без подкаталогов)
for filename in os.listdir():
    if os.path.isfile(filename):
        print(filename)
.bash_history
.bash_profile
.CFUserTextEncoding
.condarc
.DS_Store
.gitconfig
.viminfo
electors.csv
large_states.txt
myfile.txt
newfile.txt
results.csv
test_work_xjz.ipynb
Untitled.ipynb
Untitled1.ipynb
Untitled2.ipynb
Untitled3.ipynb
Untitled4.ipynb

По сути, как было указано выше, пути к файлам это обычные строки, и с ними можно производить обычные операции предусмотренные для строк. Например, если у нас в текущем рабочем каталоге есть каталог "dir2", а в нем лежит файл _"file.txt" и мы работаем под Windows, то мы можем построить относительный путь к этому файлу так: "dir2" + "\\" + "file.txt", и получим строку "dir2\\file.txt". Но гораздо аккуратнее будет соединять отдельные части пути с помощью функции os.path.join(), которая на вход получает два или больше компонента пути и создаёт строку в том формате, который поддерживается операционной системой, на которой запущен код.

In [35]:
folder = "My Nice Folder"
filename = "myfile.txt"
In [36]:
# хочу сконструировать путь к файлу с именем, лежащем в filename,
# внутри каталога, с именем, лежащим в folder
In [38]:
with open(os.path.join(folder, filename)) as f:
    print(f.read())
File in folder «My Nice Folder».

In [42]:
os.path.join("My Nice Folder", "myfile.txt")
Out[42]:
'My Nice Folder/myfile.txt'
In [43]:
os.getcwd()
Out[43]:
'/Users/teacher'

Будьте внимательны! Мир кодировок полон неожиданных сюрпризов, поэтому, всегда когда неуверены, при открытии файла на чтение или на запись прямо указывайте параметр encoding=, чтобы обозначить ту кодировку, которую хотите использовать.

In [2]:
with open("russiantext.txt", "w", encoding="utf-8") as f:
    print("Раз два три четыре пять,", file=f)
    print("Вышел зайчик погулять!", file=f)
In [3]:
with open("russiantext.txt", encoding='utf-8') as f:
    print(f.read())
Раз два три четыре пять,
Вышел зайчик погулять!

In [8]:
with open("russiantext.txt", encoding='cp1251') as f:
    print(f.read())
Раз два три четыре пять,
Вышел зайчик погулять!