פרק קודם:
פייתון 10.2 - אובייקטי רשימות ויכולותמה נלמד
- מה זה קידוד - Encoding
- קידודים שונים
- מהם קבצים
- פורמטים שונים לקבצים
- כיצד לעבוד עם קבצים בפייתון
- כיצד לעבוד עם תיקיות בפייתון
קידודים - Encoding
ההגדרה הטכנית של קידוד היא דרך המרה של מידע לצורת מידע אחרת
,
או בפשטות - לתת ייצוג למשהו בצורה שונה.
למשל השפה האנושית - בעברית פרי עץ מתוק בצבע אדום/ירוק/צהוב נקרא תפוח.
בעצם ניתן לומר שזה סוג של קידוד אם כי יש הגדרות אחרות לשפה.
לקידוד יש צורה מקורית שנשמרת בתצורה אחת.
למשל המילה python באנגלית.
אם נרצה לייצג את זה בצורה שונה - למשל קוד מורס, נבצע המרה:
1 | .--. -.-- - .... --- -. |
קידוד במחשב ובשפות תוכנה
המחשב עובד עם מספרים, 0 ו-1.
הוא אינו יכול לקלוט שפות אנושיות כמו שאנחנו מבינים אותם.
ולכן למילים אנושיות יש גם ייצוג שהמחשב מבין, למשל:
הקידוד של המילים נקרא UTF-8 והוא קידוד פופולרי מאוד.
איך זה עובד?
מכיוון שלמחשב אין קונספט של שפה אנושית אלה מספרים, הקידוד הזה בעצם לוקח כל אות וממפה אותו למספר.
ASCII
הקידוד הכי פשוט דורש מעט זיכרון וממפה רק 128 תווים.
1 | Dec Char Dec Char Dec Char Dec Char |
בשביל לקודד “python” בקידוד ASCII אנחנו נמיר את זה למספרים:
1 | 112 121 116 104 111 110 |
נסו בעצמכם
תקודדו את שמכם באנגלית בקידוד ASCII!
מכיוון שהזיכרון שהוא דורש הוא מועט הוא לא יכול להחזיק את כל השפות בעולם - בשביל זה הרחיבו את ה-ASCII לקידוד נוסף.
הנקרא UTF-8.
UTF-8
אני בכוונה לא מרחיב על העומק של הקידודים השונים.
מה שאתם צריכים לדעת שUTF-8 הוא:
- בגודל משתנה - לא כל אות בשפה אנושית באותו גודל במחשב.
- מאוד שימושי כדי לייצג את כל שפות העולם.
- מאוד פופולרי - כמעט כל קבצי הטקסט נכתבים בקידוד הזה.
להרחבת אופקים ניתן לקרוא כאן בויקיפדיה
קבצים
קבצים היו כל התיקיות והמסמכים שישבו במשרד, מחולקים בצורה מסוימת - לפי שם, סידור אנלפבתי וכדו’
יש לנו 3 תיקיות - a, b ו c.
נניח אנחנו יצרנו רשימה של שמות, החברים הטובים שלנו, ואנחנו רוצים לתייג את זה תחת a:
תיוק מסמכים היא טכניקה ישנה וצורת העבודה במחשב בעצם השאילה את הקונספט הזה.
אנחנו עובדים כפי שאנשים פעם עבדו אך בעזרת המחשב,
כל מי שבעצם עובד עם מחשב ביום יום מכיר את הקונספטים האלו.
בתכנות אנחנו מבינים אותם יותר לעומק מאשר סתם ליצור קובץ ולשים אותו בתיקייה.
פורמטים של קבצים
בדוגמא הקודמת יצרנו קובץ שמות - מה נגיד שהפורמט של הקובץ?
חשבו כמה דקות לפני שאתם קוראים הלאה.
הפורמט של הקובץ הוא טקסט רגיל או במחשב הוא נקרא txt
.
במסמך פיזי על הנייר אין לנו קידוד מסוים, אלה הקידוד שלנו זו שפה.
האם הטקסט כתוב באנגלית, עברית וכדו’…
שם של קובץ מורכב מהשם שלו וסיומת שנכללת אחרי הנקודה.
למשל:
1 | names.txt |
השם של הקובץ: names
הסיומת שלו, באנגלית נקרא extension
יהיה : txt
.
פורמטים נפוצים:
- קובץ טקסט - .txt
- קובץ פייתון - .py
- קובץ הרצה - .exe
- קובץ אינטרנט - .html
- פורמט Comma Seperate Value - .csv
- פורמט Json - .json
פורמט בינארי
קבצים בינאריים אלו קבצים שלא מייצגים טקסט אלה מידע אחר כלשהו שהוא מיוצג כמספרים.
למשל, ניצור פורמט משלנו שכל שורה מייצגת:
מספר מזהה של המוזר - מספר ייחודי לכל מוצר שמזהה אותו.
הכמות שיש לנו את המוצר במלאי.
המחיר שלו ליחידה.
1 | 0 25 19 |
המספרים בפני עצמם לא אומרים לנו כלום, אבל אם אנחנו יודעים שזה הפורמט שלנו למוצרים אז אפשר לנחש למשל, מוצר 0 יש לנו 25 יחידות כאשר הוא עולה 19 ליחידה.
תיקיות במחשב
תיקיות נועדו כדי לעזור לנו לסדר את הקבצים שלנו בצורה נוחה ושיהיה ניתן למצוא אותם.
תיקיות נכתבות כנתיב והן בנויות בצורה היררכית.
למשל:
1 | C:\files\a\names.txt |
נתיבים
בדוגמא הראשונה רשמנו נתיב מלא, אך נתיבים יכולים להיות מלאים או יחסיים.
נתיבים מלאים הם נתיבים שרואים בהם את שם הדיסק, C או D בדרך כלל.
נתיב יחסי הוא נתיב שנמצא ביחס למשהו, למשל:
1 | ..\a\names.txt |
השתי נקודות אומרות ללכת אחורה תיקייה אחת מהתיקייה שאנחנו נמצאים.
אם אנחנו רוצים לייצג את הנתיב היחסי מתוך נתיב מלא, למשל הנתיב המלא הבא:
1 | C:\files\a |
אז חיבור הנתיבים יביא לנו את זה:
1 | C:\files\a\..\a\names.txt |
בעצם הלכנו תיקייה אחת אחורה ואז קדימה חזרה לa.
כעת ניצור את התיקיות במחשב:
קבצים במחשב
במחשב ניתן ליצור קבצים ותיקיות בקלות רבה.
הנה דוגמא ליצירת קובץ:
כשיוצרים קובץ חדש, המערכת הפעלה מראה את הסיומת שלה:
אם אתם לא רואים את הסיומות, תפעילו את האפשרות:
קבצים בפייתון
כפי שראינו בפרק הראשון, פייתון מאפשרת לנו לכתוב קוד שיעשה פעולות בצורה אוטומטית.
לכן אין צורך בליצור תיקיות וקבצים כל הזמן באופן ידני.
לקרוא קבצי פייתון נעשה בעזרת הפונק’ open
שמקבלת שני פרמטרים.
הפרמטר הראשון הוא הנתיב לקובץ.
הפרמטר השני הוא המצב פתיחה שאנחנו רוצים.
ע”פ מצבים שונים נביא לו ערך שונה.
אחרי שפותחים קובץ - צריך לסגור אותו.
כמו שסוגרים
ליצור קובץ
פונק’ open
מקבלת כפרמטר שני את הצורה שבה נרצה ליצור את הקובץ:
mode | תיאור |
---|---|
r | פותח קובץ קיים לקריאה |
x | יוצר קובץ חדש |
a | יוצר קובץ אם לא קיים ומאפשר להוסיף טקסט לקובץ. |
w | יוצר קובץ אם לא קיים |
בהמשך נעבור על מה הוא מחזיר לנו ב-x
כאשר הקובץ קיים, כרגע אגיד שהוא פשוט ייכתוב לכם שהקובץ כבר קיים.
ניתן להוסיף ערך נוסף:
mode | תיאור |
---|---|
t | מתייחס לקובץ כקובץ טקסט |
b | מתייחס לקובץ כקובץ בינארי |
קובץ בינארי הוא קובץ אשר המידע בפנים יכול לייצג כל דבר ולא בהכרח טקסט שניתן לקרוא אותו.
צורת המידע היא בהתאם לפורמט ולקידוד שלו.
דוגמאות:
1 | file = open('C:\\a\\names.txt','xt') |
למה צריך שני סלאשים בנתיב?
יש ייצוג לתווים מיוחדים כמחרוזות שכותבים אותם עם סלאש אחד.
למשל יש רווח מיוחד שנקרא טאב - כמו המקש של המקלדת שלכם.
אם לוחצים על טאב זה יוצר מעיין רווח גדול, הרווח הזה מיוצג במחשב בעזרת סלאש t
:
1 | \t |
כדי לכתוב את זה במחרוזת ניתן פשוט לכתוב אותו:
1 | tab = '\t' |
אך כאשר רוצים לכתוב תרתי משמע סלאש והאות t אז צריך לרשום שני סלאשים:
1 | t = "\\t" |
המושג הזה נקרא - character escape.
כדי שיהיה ניתן לרשום כטקסט גם תווים מיוחדים כמו זה, וגם תווים רגילים, וגם סלאש כשרוצים, פייתון נותנת לנו אפשרות לעשות לתווים האלו escape.
לכתוב קובץ
אחרי שפותחים קובץ ניתן לכתוב לתוכו בעזרת שני הפונקציות write
ו- writelines
הפונקציה write
כותבת טקסט בלי שורה חדשה.writelines
רושמת לקובץ בלי שורה חדשה את כל המחרוזות.
1 | file = open('C:\\a\\names.txt','a') |
אם נרשום את זה ככה, הטקסט שיירשם בקובץ הוא:
1 | BobAliceJoeTony |
אין שורות חדשות!
אז איך בעצם רושמים אותם? בעזרת התו של השורה החדשה:
1 | newLine = '\n' |
1 | file = open('C:\\a\\names.txt','a') |
עכשיו הקובץ שלנו נראה יותר טוב:
1 | Bob |
לקרוא קובץ
שני הפונקציות שניתן להשתמש בשביל לקרוא אלו:
read
- לקרוא את כל הקובץ כמחרוזת אחת או כמות תווים שנותנים.readlines
- לקרוא את כל השורות.
לקרוא את הכל
הפונקציה קוראת את כל הקובץ,
ניתן להעביר מספר לפונקציה שאומרת מהי כמות התווים שאנו רוצים לקרוא.
1 | file = open('C:\\a\\names.txt') |
אם יש לנו קבצים יותר מדי גדולים אנחנו יכולים לחלק את הקריאות שלנו לחלקים קטנים יותר:
1 | file = open('C:\\a\\names.txt') |
לקרוא שורות
קריאת השורות נעשית בצורה מאוד פשוטה כי יש לנו כבר פונקציה לזה!
1 | file = open('C:\\a\\names.txt') |
זוכרים ש print
מדפיס שורה חדשה?
שורות חדשות בתוך קובץ מיוצגות בעזרת התו ‘\n’,
קוראים את זה “באק-סלאש n”.
בגלל שהקובץ עצמו מקודד בעזרת שורות חדשות:
1 | Bob\n |
לכן אם לא נשתמש ב end= ''
זה ידפיס לנו כל פעם שורה ריקה.
ואנחנו רוצים להימנע מזה.
תזכורת:
ה-end
נותן לנו אופציה להחליף את השורה החדשה בכל תו אחר.
מחיקה
אינדקס בקבצים
כדי למחוק קובץ אנחנו צריכים לדעת היכן אנחנו בתוך הקובץ.
מה ז”א?
תדמיינו שקובץ הוא כמו רשימה של תווים:
*זוכרים שמחרוזת היא כמו רשימה של תווים?
1 | fileContent = "Bob\nAlice\nJoe\nTony\n" |
זה כמו אינדקס ברשימה לקבצים יש גם “אינדקס” שמפנה לאיפה אנחנו נמצאים בקובץ.
ניתן לבדוק איפה אנחנו בקובץ בעזרת הפונקציה tell
.
ניתן לשנות את המיקום ע”י הפונקציה seek
.
1 | file = open("C:\\a\\names.txt","r") |
דוגמא:
מחיקה מתוך קובץ
מחיקת ספציפית מתוך קובץ אינו אפשרי, אך ניתן להגדיל מחדש קובץ בעזרת הפונקציה truncate
.
הפונקציה מקבלת גודל שמייצגת את כמות התווים שרוצים לשנות,
ואם לא מעבירים את כמות התווים אז הוא לוקח את האינדקס הנוכחי שבו הוא נמצא, ניתן לשנות את זה בעזרת seek
.
1 | file = open("C:\\a\\names.txt","a") |
מחיקת קובץ
כדי למחוק את כל הקובץ אנחנו נצטרך להשתמש בפונקציות אחרות.
נכיר את המודול - os
.os
הוא קיצור ל OperationSystem
.
על מנת למחוק נשתמש בפונקציה remove:
1 | import os |
פשוט וקל :)
יצירה ומחיקה של תיקיות
os
נותן לנו את כל הפונקציות שאנחנו צריכים כדי להתמודד עם תיקיות וקבצים.
כדי ליצור תיקייה משתמשים ב-mkdir
.
כדי למחוק תיקייה משתמשים ב-rmdir
.
1 | os.mkdir('C:\\tempDir') |
לקבל רשימת קבצים מתוך תיקייה
בעזרת הפונקציה listdir
שנמצאת במודול os
ניתן לקבל את הרשימה של הקבצים שיש לנו בתיקייה.
1 | import os |
הימנעו משימוש בשמות בעברית, ניתן לעבוד עם שמות בעברית אך בד”כ זה פחות נוח.
הדרך הנכונה יותר לפתוח קבצים
קוראים קובץ בעזרת המתודה open
.
אך מהי הבעיה הנפוצה?
קבצים שפותחים צריך לסגור, אחרת הם יישארו פתוחים ולא ייכתבו עד הסוף - וזה מתכון לבאגים.
הדרך הראשונה לטפל בזה זה לבצע סגירה לבד:
1 | file = open("file","a") |
אך כאשר הקוד שלנו גדל יכול להיות שנשכח לעשות את זה או ייקרה מצב שנצא מהתכנית שלנו מבלי לסגור אותו.
בשביל זה פייתון מגדירה לנו דרך יותר נוחה בעזרת with
.
1 | lines = [] |
התחביר של with
הוא הפתיחה ואז שם המשתנה שאנחנו נותנים לקובץ:
1 | with open(...) as <fileName>: |
אל תשכחו, הנקודותיים פותחים לנו בלוק של קוד וכך אנחנו צריכים להזיח את השורה שמתחת.
תרגילים
תכתבו תכנית אשר תקבל קלט מהמשתמש עד שהוא כותב exit.
כל קלט כזה יודפס לתוך קובץ טקסט בשורה חדשה.
בסוף התכנית (אחרי שהמשתמש כתב exit) תכתבו את מספר השורות שנכתבו לתוך הקובץ.תכתבו תכנית אשר מקבלת כקלט מהמשתמש נתיב תיקייה מסוים ותציג ברשימה עם מספרים את הקבצים.
למשל אם בתיקייה יש כמה קבצים זה יציג:1
2
31.fileOne.txt
2.names.txt
3.fileTwo.txt
לאחר מכן תינתן האופציה למשתמש לבחור מספר והתכנית תמחק את הקובץ הזה.
- כתבו תכנית שמקבלת נתיב לקובץ כקלט מהמשתמש ומדפיסה את הנתונים הבאים על הקובץ:
- שם הקובץ
- כמות התווים שיש בקובץ
- כמות השורות שיש בקובץ
4.
כתבו תכנית שקולטת מהמשתמש נתיב של קובץ והיא תצנזר מילים שהוגדרו לצנזור.
את המילים שיש לצנזר יש לשמור בקובץ נפרד הנקרא “censoredWords.txt”.
עבור הצנזור יש לשים כוכביות.
הדרך הכי פשוטה לשכתב קובץ היא למחוק אותו ולכתוב אותו מחדש!
1 |
|
התכנית הזו מממשת סוג של מחברת כאשר כל שורה נכתבת לקובץ.
זוהי דוגמא קלאסית לשמירת מידע בקובץ על מנת לקרוא אותו במידת הצורך.
1 | import os |
החלק הראשון הראשון מממש את הרשימה שצריך להביא למשתמש כדי לבחור שמות קובץ.
אנחנו מממשים את זה בעזרת רשימה פשוטה.
לאחר מכן אנחנו צריכים לקבל מספר מהמשתמש.
זוכרים שאינדקס מתחיל ב0?
לכן אם המשתמש בוחר 1 - האינדקס הסופי שנמצא במערך הוא 2.
אנחנו בודקים שהמספר תקין ובמידה וכן אנחנו מוחקים את הקובץ.
בשביל למחוק קובץ צריך נתיב מלא, ולכן אנחנו מחברים את המיקום של התיקייה עם שם הקובץ.
1 | def GetFileNameFromPath(fullPath): |
פונקציית len
מחזירה לנו את אורך הרשימה.
אנחנו יכולים להשתמש בזה גם על הרשימה של השורות וגם על השורה עצמה!
זה נותן לנו לספור את התווים והשורות שיש בקובץ.
על מנת לקבל את שם הקובץ מימשתי פונקציה בשביל זה - להמיר קטעי קוד לפונקציות קטנות זה יותר טוב.
ככה אנחנו שומרים את הלוגיקה בתוך יחידה קטנה שניתן להשתמש בה יותר מפעם אחת אם רוצים, וזה מסדר לנו את הקוד שייראה יותר טוב ויותר ברור לקריאה.
את המימוש של הפונקציה עשיתי בעזרת מתודות של מחרוזות.
rfind מוצאת את המחרוזת שמביאים לה מהכיוון ההפוך - מהסוף להתחלה.
לכן הפואנטה היא למצוא את הסלאש האחרון.
אחרי שמצאנו את הסלאש האחרון אנחנו חותכים את המחרוזת בעזרת אינדוקס.
האופרטור נקודותיים : נותן לנו לחתוך את המחרוזת ממספר מסוים עד מספר מסוים.
התחביר הוא:
[start:end]
ניתן להשתמיט את אחד מהם או שניהם כדי לומר “תתן לי מהכי התחלה או הכי סוף”.
מכיוון שאצלנו זה נראה ככה:
[start:]
אנחנו לוקחים מהמקום של ה-start ועד הסוף.
1 | def CensorLine(line, wordsToCensor): |
הדבר הראשון שאני רוצה שישימו לב אליו הם ההשמטות של התו השורה החדשה - \n.
אנחנו נמנעים מלבדוק את המחרוזת שלנו ביחד עם התווים האלו ולכן אנחנו משמיטים אותם.
לאחר מכן אנחנו מצנזרים שורה שורה מהקובץ שהמשתמש בחר ולאחר מכן אנחנו משכתבים את כל הקובץ עם השורות החדשות, המצונזרות שיצרנו.
הצנזורה עובדת בצורה מאוד פשוטה עם הפונקצייה replace
.
שהיא לוקחת מילת מקור ומחליפה אותה במילה אחרת.
את הכוכביות יצרנו בעזרת הכפל - אנחנו מכפילים את הכוכבים במספר התווים שיש במילה שאנחנו מצנזרים.
ניתן לצנזר מילים בכל צורה שהיא, כאן בחרנו לצנזר בעזרת כוכביות.
- כמובן ניתן לבצע אופטימיצזיות - לשפר את הקוד ככה שייעבוד בצורה יותר יעילה.
אך לעיתים משימות פשוטות כדאי לבצע בצורה פשוטה כדי לא להתבלבל וליצור מורכבות שניתן היה למנוע.
זהו עקרון ה-KISS, Keep it simple stupid!
קבצים מכילים מידע ובפרק הזה התמקדנו בפונקציות הכלליות של תיקיות וקבצים ובפורמטים פשוטים כמו קבצי טקסט.
בפרק הבא נרחיב את הידע על קבצים בעזרת למידה על הפורמט הבינארי וקבצים בינאריים!