הדובר: עד כה, סביר להניח כי רוב התוכניות שלך היה קצת קיקיוני. אתה מפעיל תכנית כמו מריו או חמדן. זה עושה משהו, זה אולי יבקש המשתמש למידע, להדפיס כמה פלט המסך, אבל אז, כאשר התכנית שלך נגמר, באמת אין ראיות שיש אי פעם זה היה לרוץ במקום הראשון. אני מתכוון, בטוח, ייתכן שהשארת זה ייפתח בחלון המסוף, אבל אם אתה לנקות את המסך שלך, יש באמת אין ראיות לכך שהיה קיימים. אין לנו אמצעי אחסון מידע מתמשך, מידע שקיים לאחר תכנית הפסיקה לרוץ, או שיש לנו לא עד לנקודה זו. למרבה המזל אף, ג עושה לספק לנו את היכולת כדי לעשות זאת על ידי יישום משהו שנקרא קובץ, מבנה שבעצם מייצג קובץ שבו היית להכפיל לחץ על המחשב שלך, אם אתה משמש לסביבת משתמש גרפית. בדרך כלל כאשר עובדים עם ג, אנחנו בעצם הולך לעבוד עם מצביעים לfiles-- קובץ stars-- פרט לקצת כאשר אנו מדברים על בני זוג של הפונקציות ש עובד עם מצביעי קובץ. אתה לא צריך להיות ממש חפר עמוק מדי לתוך מצביעי הבנה את עצמם. יש קצת קטנטן קטן שבו אנחנו מדברים עליהם, אבל בדרך כלל להגיש מצביעים ו מצביעים, ואילו קשורים, הם לא בדיוק אותו דבר. עכשיו מה אני מתכוון כש אני אומר נתונים מתמשכים? מה הוא הנתונים מתמשכים? למה אכפת לנו את זה? אומר, למשל, ש אתה מפעיל תכנית או ששוכתבת תכנית שמשחק, ואתה רוצה לשמור על מסלול כל המהלכים של המשתמש כך שאולי אם משהו משתבש, אתה יכול לבדוק את הקובץ בסיום המשחק. זה מה שאנחנו מתכוונים כשאנחנו מדבר על נתונים מתמשכים. במהלך הריצה שלך תכנית, קובץ נוצר. וכאשר התכנית שלך הפסיק לרוץ, קובץ שעדיין קיים במערכת שלך. ואנחנו יכולים להסתכל על זה ולבחון אותה. וכך התכנית שהייתה נקבעה ל יצר כמה נתונים מתמשכים, הנתונים קיימים לאחר התכנית סיים ריצה. עכשיו כל פונקציות אלה שעובדים עם יצירת קבצים ומניפולציה שלהם בדרכים שונות לחיות בio.h הסטנדרטי, שהוא קובץ כותרת ש סביר להניח שאתה כבר ליש"ט כולל בחלק העליון של די הרבה כל התוכניות שלך מכיוון שהוא מכיל אחד רוב הפונקציות שימושיות עבורנו, printf, שגם מאפשר לי גר בio.h. הסטנדרטי אז אתה לא צריך להלום כולל כל קבצים נוספים כנראה על מנת לעבוד עם מצביעי קובץ. עכשיו כל פונקצית מצביע קובץ, או כל אני קובץ יחיד / O, פלט קלט פונקציה, מקבלת כאחד הפרמטרים או התשומות שלה pointer-- קובץ חוץ לאחד, fopen, ש זה מה שאתה משתמש כדי לקבל את הקובץ מצביע במקום הראשון. אבל אחרי שפתחת קובץ ואתה מקבל מצביעי קובץ, אז אתה יכול להעביר אותם כ טיעונים לפונקציות השונות אנחנו הולכים לדבר על היום, כמו גם רבים אחרים כך שאתה יכול לעבוד עם קבצים. אז יש שש די אלה בסיסיים משותפים שאנחנו הולכים לדבר על היום. fopen והלוויה שלה fclose פונקציה, fgetc וfputc פונקצית לוויה שלה, וfread ותפקוד הלוויה שלה, fwrite. אז בואו לקבל זכות לתוך זה. fopen-- מה הוא עושה? ובכן, זה פותח קובץ וזה נותן לך מצביע קובץ לזה, כך שאתה יכול להשתמש ש להגיש מצביע כטיעון לכל הקובץ האחר פונקציות קלט / פלט. הדבר הכי חשוב לזכור עם fopen הוא שאחרי שפתחת קובץ או עשה שיחה כמו אחד כאן, אתה צריך לבדוק כדי לוודא ש שהמצביע שקבל אותך בחזרה אינו שווה ל null. אם לא צפה בסרטון על מצביעים, זה אולי לא הגיוני. אבל אם אתה מנסה וdereference זוכר מצביע null, התכנית שלך תהיה כנראה סובלת פילוח [לא ברור]. אנחנו רוצים לוודא שאנחנו קיבלתי בחזרה מצביע לגיטימי. הרוב המכריע של זמננו יהיה מקבל מצביע לגיטימי בחזרה וזה לא יהיה בעיה. אז איך אנחנו עושים שיחה לfopen? זה נראה פחות או יותר כמו זה. קובץ כוכב ptr-- PTR להיות גנרי שם לקובץ pointer-- fopen ואנחנו עוברים בשני דברים, שם קובץ ופעולה שאנו רוצים לבצע. אז אולי יש לנו שיחה שנראית כמו זה-- PTR כוכב קובץ 1 שווה fopen file1.txt. והפעולה שבחרתי הוא r. אז מה אתה חושב r הוא כאן? מה הם הסוגים של דברים שאנחנו ייתכן שתוכל לעשות לקבצים? אז R היא הפעולה ש לבחור מתי שאנחנו רוצים לקרוא קובץ. אז הייתי בעצם כש אנחנו עושים שיחה כזאת מקבל את עצמנו מצביע קובץ כזה שאנחנו יכולים ואז לקרוא מידע מfile1.txt. כמו כן, אנו יכולים לפתוח 2.txt קובץ לכתיבה ולכן אנחנו יכולים לעבור ptr2, מצביע הקובץ שנוצרתי כאן, כטיעון לכל פונקציה ש כותב מידע לקובץ. ודומה לכתיבה, יש גם את האפשרות לצרף,. ההבדל בין כתיבה וצירוף להיות שכשאתה כותב לקובץ, אם אתה מבצע שיחה לfopen לכתיבה וקובץ שכבר קיים, זה הולך לדרוס את הקובץ כולו. זה הולך להתחיל בהתחלה, מחיקת כל המידע זה כבר שם. לעומת זאת, אם אתה פותח אותו לשרשור, זה ילך לסוף הקובץ אם יש כבר טקסט ב זה או מידע בו, ואז זה יתחיל כתיבה משם. אז אתה לא תאבד את כל מידע שעשית לפני. אם ברצונך לכתוב או לצרף סוג של תלוי במצב. אבל אתה בטח יודע מה פעולה נכונה היא כאשר מגיע הזמן. אז זה fopen. מה לגבי fclose? ובכן, די פשוט, fclose רק מקבל את מצביע הקובץ. וכפי שאפשר לצפות, זה סוגר את התיק ש. וברגע שאנחנו כבר סגרנו קובץ, אנחנו לא יכולים לבצע כל עוד קובץ פונקציות קלט / פלט, קריאה או כתיבה, בקובץ זה. אנחנו צריכים לפתוח מחדש להגיש בפעם אחרת על מנת להמשיך לעבוד עם שלו באמצעות פונקציות קלט / פלט. אמצעי אז fclose שנסיים עבודה עם קובץ זה. וכל מה שאנחנו צריכים לעבור בהם שמו של מצביע קובץ. אז בכמה שקופיות לפני, אנחנו על מודעה נקודה 1 קובץ fopened לקריאה ואנחנו שהוקצו ש להגיש מצביע לptr1. עכשיו החלטנו שאנחנו סיימתי לקרוא מקובץ ש. אנחנו לא צריכים לעשות יותר עם זה. אנחנו יכולים רק ptr1 fclose. ובאופן דומה, יכולים אנו fclose האחרות אלה. בסדר. אז זה פתיחה וסגירה. אלה הם שני בסיסיים מתחיל את פעילות. עכשיו אנחנו רוצים בעצם לעשות כמה דברים מעניינים, והפונקציה הראשונה שנוסיף ל רואה שיעשה את זה הוא fgetc-- להגיש את אופי. זה מה שבדרך כלל fgetc היה לתרגם. שלה מטרה בחיים היא לקרוא את התו הבא, או אם זה מאוד שיחה ראשונה לfgetc לקובץ מסוים, התו הראשון. אבל אז אחרי ש, אתה מקבל ליד אחד, האופי מאוד הבא של קובץ ש, ומאחסן אותו במשתנה אופי. כפי שעשינו כאן, פרק char שווה fgetc, לעבור בשם מצביע קובץ. שוב, זה מאוד חשוב לזכור כאן כי כדי שיהיה לי פעולה זו תצליח, המצביע עצמו הקובץ בטוח נפתח לקריאה. אנחנו לא יכולים לקרוא אופי מקובץ מצביע שפתחנו לכתיבה. אז זה אחד מ מגבלות של fopen, נכון? אנחנו צריכים להגביל את עצמנו לביצוע רק פעולה אחת עם מצביע קובץ אחד. אם אנחנו רוצים לקרוא ו לכתוב מאותו הקובץ, היינו צריך לפתוח שתי נפרד מצביעי קובץ באותו file-- אחד לקריאה, אחד לכתיבה. אז שוב, הסיבה היחידה אני מביא את זה עכשיו הוא כי אם אנחנו הולכים לבצע שיחה לfgetc, שזה בטח מצביע קובץ נפתח לקריאה. ואז די פשוט, כל מה שאנחנו צריכים לעשות הוא להעביר בשמו של מצביע הקובץ. אז פרק char שווה ptr1 fgetc. זה הולך לגרום לנו character-- הבא או שוב, אם זה ראשון זמן שעשינו את השיחה הזאת, character-- הראשון של מה ש הקובץ הצביע על ידי ptr1. נזכיר כי זה היה טקסט נקודת קובץ 1. זה יהיה לקבל את התו הראשון של ש ואנחנו לאחסן אותו בפרק משתנה. די פשוט. אז בדקנו רק בשלוש פונקציות וכבר אנחנו יכול לעשות משהו די מסודר. אז אם אנחנו לוקחים את היכולת הזו מקבל אופי ואנחנו לולאה it-- כדי ש תמשיך לקבל תווים מקובץ שוב ו שוב ועכשיו אנחנו over-- יכול לקרוא כל אחד דמותו של קובץ. ואם אנחנו להדפיס כל דמות מייד לאחר שקראנו אותו, כעת אנו קוראים מקובץ ו מודפס התוכן שלה אל המסך. אנחנו כבר בשרשור ביעילות קובץ שעל המסך. וזה מה ש פקודת חתול Linux עושה. אם תקליד חתול בשם הקובץ, זה יהיה להדפיס את כל התוכן של הקובץ בחלון המסוף שלך. וכך הלולאה הקטנה הזה כאן, רק שלוש שורות של קוד, אבל בו ביעילות כפילויות פקודת חתול לינוקס. אז אולי זה תחביר נראה קצת מוזר, אבל הנה מה שקורה כאן. בעוד פרק שווה fgetc, PTR הוא לא שווה לEOF-- זה כל פה מלא, אבל בואו לשבור אותו רק אז זה ברור על התחביר. אני כבר מאוחד זה למען החלל, למרות שזה קצת מבחינה תחבירית מסובך. אז את החלק הזה בימין ירוק עכשיו, מה הוא עושה? ובכן, זה רק שיחת fgetc, נכון? ראינו את זה לפני. זה קבלת אחת דמות מהקובץ. אז להשוות את זה אופי נגד EOF. EOF הוא ערך מיוחד זה שהוגדר בio.h הסטנדרטי, ש סופו של דמות קובץ. אז בעצם מה שהולך לקרות הוא לולאה זה לקרוא תווים, להשוות אותו לEOF, סוף אופי קובץ. אם הם אינם תואמים, כך שיש לנו לא הגיע לסוף הקובץ, אנחנו להדפיס את הדמות ש. אז נחזור ל החל מהלולאה שוב. אנחנו נקבל אופי, לבדוק נגד EOF, להדפיס אותו, וכן הלאה וכן הלאה וכן הלאה, לולאה דרך שבדרך עד שהגענו לסוף הקובץ. ולאחר מכן על ידי נקודה ש, תהיה לנו מודפסים את כל התוכן של הקובץ. אז שוב, שראינו רק fopen, fclose, וfgetc וכבר אנחנו יכולים לשכפל פקודת מסוף לינוקס. כפי שאמרתי בהתחלה, היו לנו fgetc וfputc, וfputc היה הלוויה פונקציה של fgetc. וכך, כפי שאתה יכול לדמיין, זה שווה ערך הכתיבה. זה מאפשר לנו לכתוב תו בודד לקובץ. שוב, האזהרה להיות, רק כמו שזה היה עם fgetc, הקובץ שאנחנו כותבים לזה בטח היה נפתח לכתיבה או לצירוף. אם תנסו ולהשתמש fputc על קובץ שאנחנו כבר פתוחים לקריאה, אנחנו הולכים לסבול קצת טעות. אבל השיחה היא די פשוט. הון fputc ptr2, כל זה הולך לעשות הוא זה הולך לכתוב המכתב ללתוך קובץ 2 נקודה טקסט, שהיה שמו של קובץ שפתחנו והוקצינו המצביע לptr2. אז אנחנו הולכים לכתוב הון לקובץ טקסט נקודה 2. ואנחנו לכתוב קריאה להצביע להגיש 3 נקודות טקסט, שהצביע על ידי ptr3. אז שוב, די פשוט כאן. אבל עכשיו אנחנו יכולים לעשות דבר אחר. יש לנו דוגמא זו אנחנו פשוט הולכים על על היכולת לשכפל את החתול פקודת לינוקס, אחד שמדפיס למסך. ובכן, עכשיו שיש לנו את היכולת לקרוא תווים מהקבצים ולכתוב תווים לקבצים, למה אנחנו לא רק להחליף ש קורא לprintf בקריאה לfputc. ועכשיו אנחנו כבר משוכפלים cp, הפקודה לינוקס מאוד בסיסית שדיברנו על דרך ארוכה לפני בפקודות לינוקס וידאו. יש לנו בצורה יעילה משוכפל שממש כאן. אנחנו קוראים אופי ולאחר מכן אנחנו כתיבת דמות שלקובץ אחר. קריאה מקובץ אחד, כתיבה למשנהו, שוב ושוב ושוב, עד שנגיע EOF. יש לנו בסופו של קובץ שאנחנו מנסים להעתיק מ. ועל ידי שאנחנו כתבנו את כל הדמויות שאנחנו צריכים את הקובץ שאנחנו כותבים. אז זה cp, עותק הפקודה לינוקס. בתחילת מאוד בסרטון זה, היה לי האזהרה שהיינו מדבר קצת על מצביעים. הנה במיוחד שבו אנו נמצאים הולך לדבר על מצביעים בנוסף להגיש מצביעים. אז פונקציה זו נראית די מפחידה. יש לו כמה פרמטרים. יש הרבה קורה כאן. יש הרבה שונה צבעים וטקסטים. אבל באמת, זה פשוט גרסה הגנרית של fgetc המאפשר לנו לקבל כל כמות המידע. זה יכול להיות קצת לא יעיל אם אנחנו מקבל תו אחד בכל פעם, iterating דרך הקובץ תו אחד בכל פעם. האם לא יהיה זה נחמד לקבל 100 בכל פעם או 500 בכל פעם? ובכן, fread ותפקוד הלוויה שלה fwrite, שנדברנו על בשני, תאפשר לנו לעשות בדיוק את זה. אנו יכולים לקרוא סכום שרירותי מידע מקובץ ואנו מאחסנים אותו במקום באופן זמני. במקום להיות מסוגלים רק להתאים אותו במשתנה יחידה, אולי צריך לאחסן אותו במערך. וכך, אנחנו עוברים בארבעה טיעונים לfread-- מצביע למיקום שבו אנחנו הולך לאחסון מידע, כמה גדול כל יחידה של מידע יהיה, כמה יחידות של מידע אנחנו רוצים לרכוש, ומ שקובץ שאנחנו רוצים לקבל אותם. כנראה הכי טוב מאויר עם דוגמא כאן. אז נניח שאנו מצהירים מערך של 10 מספרים שלמים. שמנו רק הכריז על מחסנית באופן שרירותי int arr 10. אז זה די פשוט. עכשיו מה שאנחנו עושים אף הוא frecall הוא שאנחנו קוראים גודל של int פעמים 10 בייטים של מידע. גודל של ההוויה int four-- זה בגודל של מספר שלם בג. אז מה שאנחנו עושים הוא שאנחנו קוראים 40 בתים בשווי של מידע מהקובץ הצביע על ידי PTR. ואנחנו אחסון אלה 40 בתים איפשהו שבו יש לנו להפריש 40 בתים בשווי של זיכרון. למרבה המזל, כבר עשה את זה על ידי הכרזת ARR, מערך שממש שם. כי הוא מסוגל אחזקה 10 יחידות ארבעה-בייט. אז בסך הכל, זה יכול להחזיק 40 בתים בשווי של מידע. ואנחנו קוראים עכשיו 40 בתים מידע מהקובץ, ואנחנו אחסונו בעיבוד. נזכיר מהווידאו על עצות ש שמו של מערך, כגון עיבוד, הוא באמת רק מצביע לאלמנט הראשון שלה. לכן, כאשר אנחנו עוברים בעיבוד שיש, אנחנו הם, למעשה, עוברים במצביע. בדומה לכך אנו יכולים לעשות זה-- אנחנו עושים לא בהכרח צריך לשמור על חיצנו הערימה. כמו כן, אנו יכולים להקצות באופן דינמי חיץ כזה, באמצעות malloc. זכור, כאשר אנחנו דינמי להקצות זיכרון, אנחנו שומרים את זה ב ערימה, לא הערימה. אבל זה עדיין חיץ. זה עדיין, במקרה זה, הוא מחזיק 640 בייטים של מידע בגלל כפול תופס שמונה בתים. ואנחנו מבקשים עבור 80 מהם. אנחנו רוצים שנהיה לי חלל להחזיק 80 זוגות. אז 80 פעמים 8 היא מידע 640 בתים. ושיחה שלfread היא איסוף 640 בייטים של מידע מהקובץ הצביע על ידי PTR ואחסונו עכשיו בarr2. עכשיו אנחנו גם יכולים לטפל fread בדיוק כמו קריאה לfgetc. במקרה זה, אנחנו רק מנסים לקבל תו אחד מהקבצים. ואנחנו לא צריכים מערך להחזיק אופי. אנחנו רק יכולים לאחסן אותו ב משתנה אופי. המלכוד, אם כי, הוא ש כאשר רק שיש לנו משתנה, אנחנו צריכים לעבור ב כתובת של משתנה ש כי זוכר ש טיעון הראשון לfread הוא מצביע למיקום ולזיכרון שבו אנחנו רוצים לאחסן את המידע. שוב, את שמו של המערך הוא מצביע. אז אנחנו לא צריכים לעשות מערך אמפרסנד. אבל ג, ג האופי כאן, הוא לא מערך. זה רק משתנה. ולכן אנחנו צריכים לעבור אמפרסנד ג כדי לציין שזה הכתובת שבה אנחנו רוצים לאחסן בייט אחד של מידע, דמות אחת זה ש אנחנו אוספים מPTR. Fwrite-- אני אלך דרך זה קצת יותר quickly-- הוא פחות או יותר מקבילה של fread מדויקת מלבד זה לכתיבה במקום קריאה, רק כמו other-- שהיינו לנו פתוח וקרוב, תקבל אופי, לכתוב אופי. עכשיו זה מקבל שרירותי כמות המידע, סכום שרירותי תקין של מידע. אז בדיוק כמו לפני, אנחנו יכולים יש מערך של 10 מספרים שלמים שבו כבר יש לנו מידע מאוחסן, אולי. זה היה כנראה כמה שורות קוד כי צריך ללכת בין שני אלה שבו אני ממלא ARR עם משהו משמעותי. אני ממלא אותו עם 10 מספרים שלמים שונים. ובמקום זאת, מה שאני עושה כותב מעיבוד ואיסוף המידע מעיבוד. ואני לוקח את המידע ש ומכניס אותו לתוך הקובץ. אז במקום שזה יהיה מ הקובץ למאגר, עכשיו אנחנו הולכים מ החיץ לקובץ. אז זה בדיוק ההפך. אז שוב, בדיוק כמו לפני, אנחנו יכולים גם נתח ערימה של זיכרון שיש לנו באופן דינמי הוקצה ולקרוא שמ ולכתוב את זה לקובץ. ויש לנו גם משתנה אחד מסוגל להחזיק בית אחד של מידע, כגון אופי. אבל שוב, אנחנו צריכים לעבור ב הכתובת של משתנה ש כאשר אנו רוצים לקרוא ממנה. אז אנחנו יכולים לכתוב את המידע אנו מוצאים בכתובת ש למצביע הקובץ, PTR. יש הרבה אחרים פונקציות קלט / פלט קובץ גדול שעושים דברים שונים מלבד אלה שדיברנו על היום. כמה מאלה אתה עלול למצוא את שימושי הם fgets וfputs, שהם שווי הערך של fgetc וfputc אלא גם לקריאה מחרוזת אחת מקובץ. במקום תו בודד, זה יהיה לקרוא כל מחרוזת. fprintf, אשר בעצם מאפשרת לך להשתמש printf לכתוב לקובץ. אז בדיוק כמו שאתה יכול לעשות החלפה משתנה באמצעות ואני אחוזים מצייני מיקום ד אחוזים, וכן הלאה, עם printf אתה יכול לקחת באופן דומה מחרוזת printf והדפסת משהו כמו שלקובץ. fseek-- אם יש לך נגן DVD היא האנלוגיה אני בדרך כלל להשתמש כאן-- הוא כמו סוג של השימוש שלך אחורה וקדימה במהירות כפתורים כדי לנוע הסרט. כמו כן, אתה יכול להסתובב הקובץ. אחד הדברים בתוך שמבנה הקובץ ג שיוצר עבורך הוא אינדיקטור היכן אתה נמצא בקובץ. האם אתה במאוד מתחיל, בבתי אפס? האם אתה בייט 100, בתים 1,000, וכן הלאה? אתה יכול להשתמש בfseek לנוע באופן שרירותי מחוון שקדימה או אחורה. וftell, שוב בדומה לנגן DVD, הוא כמו שעון קטן שאומר לי לך כמה דקות ושניות ש הם לסרט מסוים. באופן דומה, ftell אומר לך איך בתים רבים אתה לתוך הקובץ. feof היא גרסה שונה גילוי אם יש לך הגיע לסוף הקובץ. וferror הוא פונקציה שאתה יכול להשתמש כדי לזהות אם משהו יש הלך עבודה לא בסדר עם קובץ. שוב, זה רק מגרד את פני השטח. יש עדיין הרבה יותר קובץ קלט / פלט פונקציות בio.h. הסטנדרטי אבל זה כנראה יקבל אותך התחיל לעבוד עם מצביעי קובץ. אני דאג לויד. זה cs50.