Вступ
На останньому уроці ми з вами навчились імпортувати та використовувати код з інших модулів. На цьому ж уроці спробуємо трішки розібратися з роботою з файлами, як їх відкривати, записувати дані і навіть як зберігати та відновлювати цілі екземпляри (так – Пітонівські об’єкти) напряму у файли. Забули що означає термін Екземпляр? Тоді пропоную пригадати один з попередніх уроків про Класи у мові Python.
Відкривання Файлу
Для того, щоб відкрити файл, ми зазвичай користуємося вбудованою у мову Пітон функцією ‘open’. Дана функція отримує ряд аргументів, якими ми повідомляємо чи хочемо читати з файла, а чи можливо навпаки записати дані у нього, ну і звичайно передаємо шлях до самого файла. Отже, давайте на живому прикладі спробуємо відкрити файл для читання (у режимі read – ‘r’ ):
1 2 3 4 5 6 7 8 |
# відкриваємо файл my_file.txt, що знаходиться всередині папки # Documents; відкриваємо його для читання - другий аргумент є 'r' (read) myfile = open('/Documents/my_file.txt', 'r')
# а тепер вичитуємо весь вміст файлу my_file.txt з допомогою метода # read вказівника файлу (так званого дескриптора - у нашому випадку myfile); # виводимо це все на екран print myfile.read() |
У вище наведеному прикладі функція ‘open’ повернула так званий дескриптор файлу, який ми потім пожемо прочитати, щоб отримати вміст нашого відкритого файлу. Метод read об’єкта відкритого файлу myfile вичитує і повертає весь вміст нашого файлу.
Шукай і знайдеш!
А тепер самі спробуйте у вашій програмі відкрити, вичитати і вивести на екран вміст будь-якого непорожнього текстового файлу на вашому диску. Як спробуєте, тоді лише продовжуйте далі даний урок… Я чекаю…
… Ну як, вдалось? Якщо ні, то які проблеми трапилися? Запостіть деталі в коментарі – допоможу розібратися.
А для тих, кому вдалося, пропоную ще раз запустити останній рядочок своєї програми. Там де є виклик метода ‘read’:
1 |
print myfile.read() |
Що отримали? Порожню стрічку. Це тому, що наш ‘курсор’ змінив свою позицію під час першого прочитання усього вмісту файлу (тоді коли ми вперше викликали метод ‘read’).
Що таке курсор? З курсором ви мабуть вже зустрічалися у своєму улюбленому редакторі коду. Це поточна ваша позиція у документі чи файлі. Це та позиція, звідки ви почнете вводити ваш текст. Також використовуючи клавіші стрілочок ви можете переміщувати курсор на нову позицію у файлі. Так от, такий самий принцип курсора при вичитуванні файла з допомогою коду на мові Пітон.
Курсор напряму повідомляє функції ‘read’ (та й в принципі усім іншим функцям вводу та виводу) звідки починати працювати з відкритим файлом. Курсор автоматично переміщається по файлу по мірі його прочитання. Таким чином при використанні функції ‘read’, ми вичитуємо повний вміст файлу, а отже отримуємо наш курсор на останній позиції у файлі – у самому кінці. Саме тому повторний виклик функції read повертає нам порожню стрічку. Функція починає вичитувати з позиції курсора, який на той момент є в кінці файлу, тому і вичитувати вже нічого.
Що ж робити? А є інший спосіб переміщати курсор у файлі – це використання методу ‘seek’ (з англ. ‘шукати’). Дана функція використовується у вигляді seek(offset, whence).
Параметр ‘whence’ є необов’язковим та визначає позицію звідки починати пошук у файлі. Якщо ‘whence’ є рівним нулю (0), тоді байти (символи) у файлі відраховуються від початку файла. Якщо 1 – тоді байти відраховуються від поточної позиції курсора. Якщо 2 – тоді байти відраховуються починаючи з кінця файла. Якщо аргумент ‘whence’ ми не передаємо, то його значення по замовчуванню є рівним 0.
Аргумент ‘offset’ описує як далеко від позиції ‘whence’ ми перемістимо курсор. Давайте пройдемось по кількох прикладах:
· myfile.seek(45, 0) – переміщаємо курсор на 45 байт (символів) відносно початку файлу
· myfile.seek(10, 1) – переміщаємо курсор на 10 байт (символів) відносно поточної позиції курсору
· myfile.seek(-77, 2) – переміщаємо курсор на 77 байт (символів) відносно кінця файлу (зауважте, що у цьому випадку ‘offset’ має бути від’ємним, позначаючи рух курсора справа – наліво)
А тепер спробуйте самі поекспериментувати з методом ‘seek’. Використовуйте даний метод, щоб переміщати курсор на будь-яку позицію у файлі. Одним із найпоширеніших його використань є переміщення курсора на початок файлу для повторного вичитування вмісту файлу.
Тобто, щоб повторно отримати вміст файлу, після першого виклику read(), нам треба скористатися викликом:
1 |
myfile.seek(0) |
Тепер коли ми знаємо базу: методи ‘read’ та ‘seek’, давайте розглянемо інші не менш корисні функцій роботи з файловим вводом та виводом у Пітоні.
Інші Функції Вводу та Виводу
Існує маса інших функцій для роботи з файлами. Ці функції мають багато застосувань, що дають нам змогу робити багато різних речей значно простіше. Давайте розглянемо з вами функції tell, readline, readlines, write та функцію close.
tell() - дана фукція повертає поточну позицію курсора у файлі. Вона не приймає жодних параметрів, просто викликаєте її з порожніми дужками і отримуєте число – позицію курсора. Дана функція є неймовірно корисною при читання з файлу.
readline() - вичитує дані з файлу починаючи з поточної позиції курсора і аж до кінця поточного рядка. Пам’ятайте, що кінець рядка – це не там де закінчується ваш екран монітора – рядок закінчується там, де натискаєте Enter (клавіша переводу на новий рядок), щоб створити новий рядок. Дана функція може бути корисною при вичитуванні файлів логування подій, або для того, щоб пробігатись по даних частинами, щоб потім їх по-трохи обробляти. readline також не приймає ніяких параметрів.
readlines() - ця функція дуже схожа на функцію readline(), проте вона вичитує усі рядочки до самого кінця файлу. А починає читати так само – від поточної позиції курсора у відкритому файлі. Дана функція повертає список із стрічок, де кожна стрічка містить рядок символів (тексту) із файлу. Наприклад, якщо б ми мали текстовий файл із наступним вмістом:
1 2 3 4 5 6 |
Hello World
We are the Champions My name is Vova
Last Line in My File |
тоді наша функція readlines() повернула б наступні результати:
1 2 3 |
>>> myfile = open('hello.txt', 'r') >>> myfile.readlines() ['\n', 'Hello World\n', '\n', 'We are the Champions\n', 'My name is Vova\n', '\n', 'Last Line in My File\n'] |
Ми отримали список стрічок. Зауважте символи ‘\n’ – це і є якраз ті сами переводи на наступний рядок, результат натискання клавіші Enter.
write() – ця функція записує дані у файл. Вона також поважає позицію курсора і починає писати у файл починаючи від нього, переписуючи наново (тобто перетираючи) усі наступні після курсора символи. Приблизно так само як в Microsoft Word, коли ви натискаєте режим заміни (Insert) і починаєте надписувати новий текст поверх існуючого. Дана функція приймає один параметр, який, власне, і є тими даними (стрічкою, текстом) для запису у файл. Приклад:
1 2 |
>>> myfile.open('to_write.txt', 'w') myfile.write('Hello World') |
Зверніть увагу, що у прикладі зверху ми відкрили файл у режимі запису, передавши функції ‘open’ другим параметром символ ‘w’ (write).
А тепер спробуйте відкрити будь-який тестовий файл (або створити) і використовуючи вище наведені функції поекспериментуйте з даним файлом і його вмістом. Знаючи вище наведені функції, ми з вами можемо програмувати майже будь-який файловий редагувальний процес.
Пікли (Pickles), або як зберегти дані у файл
Pickles з англійської перекладається як закрутка, соління. Тобто щось законсервоване в банку, як наприклад мариновані огірки Піклами в Пітоні називають збережені у файл екземпляри класів чи інші об’єкти. Об’єктами, як ми уже з вами знаємо, у мові Python є будь-яка сутність: змінна, інстанс класу, список, словник, функція, і т.д. Інші об’єкти також можуть бути “запіклені”, але є певні обмеження.
Після збереження в “пікл”, об’єкт пізніше може бути відновленим. Таким чином ми, можна сказати зберігаємо об’єкти.
Отож, як саме ми засолюємо (піклимо, зберігаємо) об’єкти? А дуже просто. В Пітоні є модуль pickle, в якумо у свою чергу, знаходиться функція dump(), яка і робить усю важку роботу для нас. Досить просто? Давайте зараз з вами на прикладі спробуємо імпортувати функцію dump та скористатися нею, щоб зберегти об’єкт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# модуль testpickle.py
# імпортуємо необхідні нам речі import pickle
# давайте створимо словник, який потім і спробуємо запіклити mylist = ['hello', 3, 'ten', 10, 'nice day today']
# створимо новий файл, для цього відкриємо поки неіснуючий файл у режимі # для писання - 'w'; при відкриванні пітон створить нам # поки неіснуючий файл myfile = open('my_file.db', 'w')
# а тепер збережемо наш словник використовуючи функцію dump # функція dump отримує два аргумента: дані, які треба зберігати; # а другим параметром - відкритий для читання файл - куди писати pickle.dump(mylist, myfile)
# ну і на кінець не забуваймо закривати відкритий файл myfile.close() |
Спробуйте самі набрати вище наведений приклад у свому редакторі і запустити його. Після цього перевірте чи був створений новий файл myfile.db. Спробуйте відкрити і подивитися що всередині. А всередині буде те, що ми часто називаємо незрозумілими ієрогліфами. Це бінарний код, спеціальне представлення збережних пітоніських об’єктів, яке аж ніяк не призначене для людських очей Тому не переживайте, цей файл записала машина, тому машині її і вичитувати назад.
Отже, тепер давайте спробуємо з допомогою оберненої функції, під назвою load(), вичитати назад наш словник.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# модуль testunpickle.py
# імпортуємо необхідні нам речі import pickle
# відкриваємо наш попередньо записаний файл, але цього разу для читання # зауважте, що режим відкривання файла є 'rb': r - читати (read), b - бінарний режим, # тобто даємо знати пітону, що файл містить не текстові дані myfile = open('my_file.db', 'rb')
# завантажуємо дані з файлу використовуючи функцію load модуля unpickle # Зверніть увагу: функція приймає відкритий файл, а не готові дані пікла mylist = pickle.load(myfile)
# можемо закрити наш файл myfile.close()
# роздрукуємо те, що в завантаженому списку, мають бути ті ж елементи, що ми # початково додали у наш список перед 'консервуванням' його у файл for item in mylist: print item |
Виглядає круто, так? Але тут є одне обмеження, таким чином ми можемо зберегти лише один список (чи інший об’єкт) у один окремий файл. Але це обмеження можна обійти, наприклад, поклавши різні об’єкти для збереження у словник чи список, а вже той словник чи список – запіклити.
Загалом все по піклах.
Я неодноразово використовував пікли, щоб обійтись без повноцінної бази даних у невеличких проектах. Навіть Plone CMS (Zope фреймворк) використовують об’єктну базу даних – ZODB, яка використовує трохи розширений механізм Пітонівських піклів.
Думаю вам також може приходитись такий механіз для бази у одному з вашим майбутніх проектів.
На закінчення
Тепер ми з вами вміємо працювати з файлами, читати і записувати в них, а також рухатись посимвольно по файлах. Також знаємо, що таке пікли та де їх можна застосувати.
Гарна робота!
У наступному, і останньому уроці, ми з вами розглянемо тему Помилок. Як їх виловлювати, як правильно їх обробляти, і взагалі що таке помилка. Також як її правильно розуміти.
Виникли труднощі із запуском прикладів коду? Знайшли помилки? Маєте доповнення? Коментуйте у формі нижче! Я відповів на кожен коментар!
Чекаю на ваші коментарі: