[Powered by Google Translate] [קובץ I / O]
[ג'ייסון הירשהורן, אוניברסיטת הרווארד]
[זה CS50, CS50.TV]
כאשר אנו חושבים על קובץ, מה שעולה על דעת הוא מסמך Microsoft Word,
תמונת JPEG, או שיר MP3,
והאינטראקציה שלנו עם כל אחד מסוגי קבצים אלה בדרכים שונות.
לדוגמה, במסמך Word להוסיף טקסט
ואילו בתמונת JPEG אנחנו עלולים לחתוך את הקצוות או לרטש את הצבעים.
עם זאת, מתחת למכסת המנוע של כל קבצים במחשב שלנו הם לא יותר
מרצף ארוך של אפסים ואחדים.
זה תלוי ביישום הספציפי שמקיים אינטראקציה עם הקובץ
כדי להחליט כיצד תהליך ארוך הרצף הזה ולהציג אותו למשתמש.
מצד אחד, מסמך עשוי להסתכל רק בית אחד,
או 8 אפסים ואחדים, ולהציג תו ASCII על המסך.
מצד השני, תמונת מפה סיבית יכולה להסתכל על 3 בתים,
או 24 אפסים ואחדים,
ומפרש אותם כ3 מספרים הקסדצימליים
שמייצגים את הערכים עבור אדום, ירוק וכחול
בפיקסל אחד של תמונה.
כל מה שהם עשויים להיראות על המסך שלך, בליבה שלהם,
קבצים הם לא יותר מאשר רצף של אפסים ואחדים.
אז בואו לצלול פנימה ולהסתכל על איך שאנחנו משחקים באפסים והאחדים הללו בעצם
כשזה מגיע לכתיבה ולקריאה מקובץ.
>> אני מתכוון להתחיל על ידי פירוקו לתהליך פשוט 3-חלק.
בשלב בא, אני אצלול לשתי דוגמאות קוד המדגימים שלושה החלקים הללו.
לבסוף, אני אבדוק את התהליך וחלק מהפרטים החשובים ביותר שלה.
כמו בכל קובץ שיושב על שולחן העבודה שלך,
הדבר הראשון שיש לעשות הוא לפתוח אותו.
ב C אנו עושים זאת על ידי ההכרזה מצביעה ל struct מוגדר מראש
שמייצג את קובץ בדיסק.
בקריאה לפונקציה הזאת, אנחנו גם להחליט אם אנחנו רוצים לכתוב או לקרוא מהקובץ.
בשלב בא, אנחנו עושים את הקריאה וכתיבה עוצמה.
ישנן מספר הפונקציות מיוחדות שאנחנו יכולים להשתמש בחלק זה,
וכמעט כולם מתחילים באות F, אשר עומד על קובץ.
אחרון, בדומה לX האדום הקטן בפינה העליונה של הקבצים הפתוחים במחשב שלך,
אנחנו סוגרים את הקובץ עם קריאה לפונקציה סופית.
עכשיו שיש לנו מושג כללי על מה שאנחנו הולכים לעשות,
בואו לצלול לתוך הקוד.
>> במדריך זה, יש לנו שני קבצי C וקבצי ההפעלה המקביל שלהם.
התכנית לוקחת מכונת כתיבת טיעון שורת פקודה אחת,
שמו של המסמך שאנחנו רוצים ליצור.
במקרה זה, אנחנו קוראים לזה doc.txt.
בואו להפעיל את התכנית ולהיכנס כמה שורות.
היי. השמי הוא ג'ייסון.
לבסוף, אנו מקלידים "התפטרנו".
אם עכשיו רשימה של כל קבצים בספרייה זו,
אנו רואים כי קיים מסמך חדש נקרא doc.txt.
זה הקובץ זה עתה יצר תכנית.
וכמובן, גם היא לא יותר מאשר רצף ארוך של אפסים ואחדים.
אם נפתח הקובץ החדש הזה,
אנו רואים את 3 שורות של קוד שנכנסנו לתכנית שלנו -
היי. שם מאי הוא ג'ייסון.
אך מה שבאמת קורה כאשר typewriter.c פועל?
השורה הראשונה של ריבית עבורנו היא 24 קו.
בקו הזה, אנו מצהירים מצביע הקובץ שלנו.
הפונקציה המחזירה את מצביע זה, fopen, לוקחת שני טיעונים.
הראשון הוא שם הקובץ כולל סיומת הקובץ, אם מתאים.
תזכיר כי סיומת קובץ אינה משפיעה על הקובץ ברמה הנמוכה ביותר.
אנחנו תמיד להתמודד עם רצף ארוך של אפסים ואחדים.
אבל זה עושה השפעה כמה קבצים ויישומים פרשו מה הם משמשים לפתיחתם.
הטיעון השני לfopen הוא אות אחת
שמייצג את מה שאנחנו מתכננים לעשות אחרי שפותחים את הקובץ.
ישנן שלוש אפשרויות לטיעון זה - W, R, וא
אנחנו בחרנו w במקרה זה משום שאנחנו רוצים לכתוב לקובץ.
R, כפי שאתם יכולים לנחש, הוא לקריאה לקובץ.
וזה לשרשור לקובץ.
בעוד הן w וניתן להשתמש בו לכתיבה לקבצים,
w יתחיל לכתוב מההתחלה של הקובץ
ואפשרות להחליף את כל נתונים, כי בעבר היה מאוחסנים.
כברירת מחדל, קובץ נפתחנו, אם הוא לא קיים,
נוצר בספרייה שלנו עובדת כיום.
עם זאת, אם אנחנו רוצים לגשת או ליצור קובץ במיקום אחר,
בטיעון הראשון של fopen,
אנחנו יכולים לציין נתיב קובץ בנוסף לשם הקובץ.
בעוד החלק הראשון של התהליך הזה הוא רק שורה אחת של קוד ארוך,
מומלץ תמיד טוב לכלול קבוצה נוספת של קווים
שתבדוק על מנת להבטיח שהקובץ נפתח בהצלחה או שנוצר.
אם fopen מחזיר null, לא הייתי רוצה לפרוץ קדימה עם התכנית שלנו,
וזה יכול לקרות אם מערכת ההפעלה היא מתוך זיכרון
או אם ננסה לפתוח קובץ בספרייה שעבורו לא הייתה לו ההרשאות המתאימות.
>> החלק השני של התהליך מתרחש בלולאה בזמן של מכונת הכתיבה.
אנו משתמשים בפונקצית ספריית CS50 כדי לקבל קלט מהמשתמש,
ובהנחה שהם לא רוצים לצאת מהתכנית,
אנו משתמשים בפונקציה fputs לקחת המחרוזת ולכתוב אותו לקובץ.
fputs הוא רק אחת מהפונקציות הרבות שאנו יכולים להשתמש בו כדי לכתוב לקובץ.
אחרים כוללים fwrite, fputc, ואפילו fprintf.
ללא קשר לפונקציה המסוימת שלמרות שאסיים בשימוש,,
כולם צריך לדעת, באמצעות טיעוניהם,
לפחות שני דברים -
מה צריך להיות כתוב ובו היא צריכה להיות כתובה.
במקרה שלנו, קלט הוא המחרוזת שצריכה להיות כתובים
וfp הוא מצביע שמכוון אותנו למקום שאנחנו כותבים.
בתכנית זו, חלק השני של התהליך הוא די פשוט.
אנחנו פשוט לוקחים את מחרוזת מהמשתמש
והוספתו ישירות לקובץ שלנו עם מעט לשום אימות קלט או בדיקות בטחוניות.
אולם לעתים קרובות, חלק 2 ייקח את עיקר הקוד שלך.
לבסוף, חלק 3 הוא בקו 58, שבו אנחנו לסגור את התיק.
כאן אנו קוראים fclose ולהעביר את מצביע הקובץ המקורי שלנו.
בשורה שלאחר מכן, אנחנו חוזרים אפס, מסמנים את הסוף של התכנית שלנו.
וכן, חלק 3 הוא פשוט כמו זה.
>> בואו נעבור לקריאת קבצים.
חזור בספרייה שלנו יש לנו קובץ בשם printer.c.
בואו להפעיל אותו בקובץ שזה עתה יצר -
doc.txt.
תכנית זו, כפי שהשם מרמז, פשוט להדפיס את תוכן הקובץ המועברים אליו.
ויש לנו את זה.
את שורות קוד שכבר הקלידו קודם ונשמרו בdoc.txt.
היי. השמי הוא ג'ייסון.
אם אנחנו צוללים לתוך printer.c,
אנחנו רואים שהרבה קוד נראה דומה למה שאנו פשוט הסתובבנו בtypewriter.c.
ואכן קו 22, שבו פתחנו את הקובץ,
וקו 39, שבו סגרנו את הקובץ,
שניהם כמעט זהים לtypewriter.c, לחסוך לטענה שנייה fopen.
הפעם אנחנו קוראים מקובץ,
כך שבחרנו r במקום W.
לכן, בואו נתמקד בחלק השני של התהליך.
בקו 35, כתנאי שני ב4 הלולאה שלנו,
אנחנו עושים את שיחה לfgets,
פונקצית לווית fputs מקודם.
הפעם יש לנו שלוש טענות.
הראשון הוא מצביע למערך של תווים שבו יאוחסן המחרוזת.
השני הוא מספר תווים המרבי לקריאה.
והשלישי הוא מצביע לקובץ שבה אנחנו עובדים.
תוכל להבחין כי ללולאה מסתיימת כאשר fgets מחזיר null.
יש שתי סיבות שזה יכול היה לקרות.
ראשית, ייתכן שחלה טעות.
שנית, ויותר סביר, סוף הקובץ הושג ולא עוד דמויות היו לקרוא.
במקרה שאתה תוהה, שתי פונקציות קיימות שייאפשרו לנו לספר לי
שהסיבה היא הסיבה למצביע null המסוים הזה.
וגם, באופן לא מפתיע, מכיוון שהם צריכים לעשות עם העבודה עם קבצים,
גם פונקצית ferror ולהתחיל לתפקד feof באות ו.
>> לבסוף, לפני שאנחנו מסיקים, הערה אחת מהירה על סיום תפקיד קובץ,
אשר, כפי שהזכיר זה עתה, נכתב כfeof.
לעתים קרובות תמצא את עצמך משתמש בזמן וללולאות בהדרגה לקרוא את דרכך בקבצים.
לפיכך, תצטרך דרך לסיים לולאות אלה לאחר שתגיע לסוף של קבצים אלה.
קוראים feof על מצביע הקובץ שלך ובדיקה כדי לראות אם זה נכון
היה עושה בדיוק את זה.
לפיכך, בעוד לולאה עם התנאי (! Feof (FP)) אולי נראית כמו פתרון מושלם מתאים.
עם זאת, אומר שיש לנו שורה אחת השאירה בקובץ הטקסט שלנו.
אנחנו להיכנס הלולאה בזמננו והכל יסתדר כמתוכנן.
בסיבוב הבא דרך, התכנית שלנו תהיה לבדוק אם feof של fp הוא נכון,
אבל - וזו נקודה חשובה להבין כאן -
זה לא יהיה נכון כרגע.
זאת משום שהמטרה היא feof לא לבדוק
אם השיחה הבאה לפונקציה לקרוא תפגע סוף הקובץ,
אלא כדי לבדוק אם לא הסוף של הקובץ כבר הגיע.
במקרה של דוגמה זו,
לקרוא את השורה האחרונה של הקובץ שלנו עובר בצורה חלקה לחלוטין,
אבל התכנית עדיין אינה יודעת שאנחנו נגיע לסוף הקובץ שלנו.
זה לא שהיא עושה עד לקריאה נוספת אחת שדלפקי סוף הקובץ.
לפיכך, מצב נכון יהיה הבא:
fgets ושלושה טיעוניה - פלט, גודל של פלט, וFP -
וכל זה אינו שווה לnull.
זו הגישה שנקטנו בprinter.c,
ובמקרה הזה, לאחר יציאת לולאה,
אתה יכול לקרוא לfeof או ferror להודיע ​​למשתמש כלהנמקה הספציפית ליציאה מהלולאה הזו.
>> כתיבה ולקריאת מקובץ היא, ברמה הבסיסית ביותר,
תהליך פשוט 3-חלק.
ראשית, עלינו לפתוח את הקובץ.
שנית, אנחנו שמים כמה דברים לקובץ שלנו או לקחת כמה דברים מחוץ לזה.
שלישית, אנו לסגור את התיק.
החלקים הראשונים ואחרונים הם קלים.
החלק האמצעי הוא מקום שבי החומר המסובך שקרים.
ולמרות שמתחת למכסת המנוע שאנחנו תמיד להתמודד עם רצף ארוך של אפסים ואחדים,
זה עוזר כאשר קידוד כדי להוסיף שכבה של הפשטה
שהופך את הרצף למשהו שדומה יותר למה שאנחנו רגילים לראות.
לדוגמה, אם אנחנו עובדים עם קובץ מפה סיבית 24-bit,
אנחנו בטח יהיו קריאה או כתיבה של 3 בתים בכל פעם.
במקרה כזה, זה יהיה הגיוני להגדיר כראוי ושם
struct שהוא גדול 3 בתים.
>> למרות שעבודה עם קבצים אולי נראית מסובכת,
ניצולם מאפשר לנו לעשות משהו באמת יוצא דופן.
אנחנו יכולים לשנות את מצבו של העולם מחוץ לתכנית שלנו,
אנחנו יכולים ליצור משהו שחי מעבר לחייו של התכנית שלנו,
או שאנחנו יכולים גם לשנות משהו שנוצר לפני התכנית שלנו התחילה לרוץ.
אינטראקציה עם קבצים היא חלק חזק באמת של תכנות ב C.
ואני מתרגש לראות את מה שאתה הולך ליצור עימו בקוד הבא.
השמי הוא ג'ייסון הירשהורן. זה CS50.
[CS50.TV]
>> [שחוק]
אוקיי. טייק אחד. הנה אנחנו מתחילים.
כאשר אנו חושבים על קובץ - >> אה, הרגע. סליחה.
[שחוק] אוקיי.
היי שם.
כאשר אנו חושבים על קובץ -
כאשר אתה חושב על קובץ - אוקיי. תגיד לי כשאתה מוכן.
אוי, גדול.
למרות קריאת טלפרומפטר אולי נראה - לא. שלי רע.