1 00:00:00,000 --> 00:00:02,000 [Powered by Google Translate] [文件I / O] 2 00:00:02,000 --> 00:00:04,000 [賈森·赫塞豪恩,哈佛大學] 3 00:00:04,000 --> 00:00:07,000 這是CS50,CS50.TV] 4 00:00:07,000 --> 00:00:11,000 當我們想到一個文件,想到什麼是Microsoft Word文檔, 5 00:00:11,000 --> 00:00:14,000 JPEG圖像,或一首MP3歌曲, 6 00:00:14,000 --> 00:00:17,000 和與每個這些不同的方式中的文件類型的交互。 7 00:00:17,000 --> 00:00:20,000 例如,在Word文檔中添加文本 8 00:00:20,000 --> 00:00:24,000 一個JPEG圖像時,我們可能會裁剪的邊緣或修飾的顏色。 9 00:00:24,000 --> 00:00:28,000 然而,引擎蓋下的所有的文件在我們的電腦都更 10 00:00:28,000 --> 00:00:31,000 比一個長序列的零和一。 11 00:00:31,000 --> 00:00:33,000 它是由與該文件的特定的應用程序進行交互 12 00:00:33,000 --> 00:00:38,000 決定如何處理這個長序列,並提交給用戶。 13 00:00:38,000 --> 00:00:41,000 一方面,一個文件可能看起來只是一個字節, 14 00:00:41,000 --> 00:00:45,000 或8個零和的,並顯示在屏幕上的一個ASCII字符。 15 00:00:45,000 --> 00:00:48,000 另一方面,在3個字節,位圖圖像可能看起來 16 00:00:48,000 --> 00:00:50,000 或24個0的, 17 00:00:50,000 --> 00:00:53,000 並把它們解釋為3個十六進制數字 18 00:00:53,000 --> 00:00:56,000 表示紅色,綠色,和藍色的值 19 00:00:56,000 --> 00:00:58,000 在一個像素中的圖像。 20 00:00:58,000 --> 00:01:01,000 無論它們看起來像在你的屏幕上,在他們的核心, 21 00:01:01,000 --> 00:01:05,000 文件只不過是不是一個序列的零和一。 22 00:01:05,000 --> 00:01:08,000 因此,讓我們的潛水和看我們如何實際操作這些零和一 23 00:01:08,000 --> 00:01:12,000 當它涉及到從文件的寫入和讀取。 24 00:01:12,000 --> 00:01:15,000 >> 我將首先把它分解成三部分組成的一個簡單的過程。 25 00:01:15,000 --> 00:01:19,000 接下來,我將深入到兩個代碼示例,說明這三個部分。 26 00:01:19,000 --> 00:01:23,000 最後,我會檢討的過程和它的一些最重要的細節。 27 00:01:23,000 --> 00:01:25,000 由於坐落在您的桌面上的任何文件, 28 00:01:25,000 --> 00:01:28,000 做的第一件事是打開它。 29 00:01:28,000 --> 00:01:31,000 在C語言中,我們做到這一點,聲明一個指針,指向一個預定義的結構 30 00:01:31,000 --> 00:01:33,000 代表磁盤上的文件。 31 00:01:33,000 --> 00:01:38,460 在這個函數中調用,我們還決定,我們是否要寫入或讀取的文件。 32 00:01:38,460 --> 00:01:41,660 接下來,我們做了實際的閱讀和寫作。 33 00:01:41,660 --> 00:01:44,800 有許多專門的功能,我們可以在這部分, 34 00:01:44,800 --> 00:01:48,790 和幾乎所有的人都開始用字母“F”,表示文​​件。 35 00:01:48,790 --> 00:01:53,560 最後,類似的小紅色的X在右上角的文件在您的計算機上打開, 36 00:01:53,560 --> 00:01:56,680 最後一個函數調用,我們關閉文件。 37 00:01:56,680 --> 00:01:59,540 現在,我們有一個總體思路,我們要做的是什麼, 38 00:01:59,540 --> 00:02:02,000 讓我們深入到代碼。 39 00:02:02,000 --> 00:02:06,100 >> 在這個目錄中,我們有兩個C文件和其對應的可執行文件。 40 00:02:06,100 --> 00:02:09,710 的的打字機程序需要一個命令行參數, 41 00:02:09,710 --> 00:02:12,060 我們要創建的文件的名稱。 42 00:02:12,060 --> 00:02:16,160 在這種情況下,我們叫它doc.txt的。 43 00:02:16,160 --> 00:02:19,080 讓我們來運行程序並輸入幾行。 44 00:02:19,080 --> 00:02:23,660 你好。我的名字是賈森。 45 00:02:23,660 --> 00:02:26,710 最後,我們將鍵入“退出”。 46 00:02:26,710 --> 00:02:29,720 如果我們現在在這個目錄中列出的所有文件, 47 00:02:29,720 --> 00:02:33,770 我們看到一個新的文檔存在被稱為doc.txt。 48 00:02:34,190 --> 00:02:36,110 剛創建的文件,這個程序。 49 00:02:36,110 --> 00:02:40,520 當然,它也沒有什麼更比一個長序列的零和一。 50 00:02:41,100 --> 00:02:43,260 如果我們打開這個新文件, 51 00:02:43,260 --> 00:02:45,870 我們看到了3行代碼中,我們進入到我們的程序 - 52 00:02:46,060 --> 00:02:49,060 你好。五月的名字是賈森。 53 00:02:49,580 --> 00:02:52,090 但實際上上運行時typewriter.c? 54 00:02:52,810 --> 00:02:55,520 我們感興趣的是第一行第24行。 55 00:02:55,560 --> 00:02:58,490 在這條線,我們宣布我們的文件指針。 56 00:02:59,080 --> 00:03:03,140 函數,返回this指針,FOPEN,需要兩個參數。 57 00:03:03,140 --> 00:03:07,440 第一個是文件名,包括文件的擴展名(如適用)。 58 00:03:07,440 --> 00:03:10,980 回想一下,不影響文件的文件擴展名的最低水平。 59 00:03:10,980 --> 00:03:14,640 我們一直在處理一個長序列的零和一。 60 00:03:14,640 --> 00:03:19,630 但它確實會影響文件的解釋和使用哪些應用程序打開。 61 00:03:19,630 --> 00:03:22,290 的FOPEN的第二個參數是一個單一的字母 62 00:03:22,290 --> 00:03:25,300 代表我們打開文件後,我們打算做什麼。 63 00:03:25,300 --> 00:03:30,630 這種說法有三個選項 - W,R,和A. 64 00:03:30,630 --> 00:03:34,900 我們選擇w在這種情況下,因為我們要寫入的文件。 65 00:03:34,900 --> 00:03:38,820 R,你可能已經猜到了,是閱讀文件。 66 00:03:38,820 --> 00:03:41,760 一個是附加到文件。 67 00:03:41,760 --> 00:03:44,960 雖然兩者w和可用於寫入文件, 68 00:03:44,960 --> 00:03:47,460 w將開始編寫的文件從一開始就 69 00:03:47,460 --> 00:03:50,810 和潛在的覆蓋任何先前已被存儲的數據。 70 00:03:50,810 --> 00:03:54,070 默認情況下,我們打開的文件,如果它已經不存在, 71 00:03:54,070 --> 00:03:57,180 是建立在我們的當前工作目錄。 72 00:03:57,180 --> 00:04:00,540 但是,如果我們要訪問或創建一個文件在不同的位置, 73 00:04:00,540 --> 00:04:02,650 在第一個參數的FOPEN, 74 00:04:02,650 --> 00:04:05,840 除了文件名中,我們可以指定一個文件路徑。 75 00:04:05,840 --> 00:04:09,490 雖然這個過程的第一部分是只有一行代碼長, 76 00:04:09,490 --> 00:04:12,350 它總是個好習慣,另一組線 77 00:04:12,350 --> 00:04:15,930 檢查,以確保該文件被成功打開或創建。 78 00:04:15,930 --> 00:04:20,300 如果FOPEN返回null,我們不希望我們的計劃,開拓進取, 79 00:04:20,300 --> 00:04:23,270 這可能發生,如果操作系統的內存 80 00:04:23,270 --> 00:04:27,940 或者,如果我們試圖打開一個文件,一個目錄,而我們沒有適當的權限。 81 00:04:27,940 --> 00:04:31,780 >> 第二部分的過程中發生在打字機的while循環。 82 00:04:31,780 --> 00:04:35,000 我們使用CS50的庫函數來獲取來自用戶的輸入, 83 00:04:35,000 --> 00:04:37,190 並假設他們不想退出程序, 84 00:04:37,190 --> 00:04:41,940 我們使用的功能FPUTS的的字符串,並寫入的文件。 85 00:04:41,940 --> 00:04:46,700 FPUTS是唯一的眾多功能之一,我們可以用它來寫的文件。 86 00:04:46,700 --> 00:04:51,920 其他包括的FWRITE,的fputc,甚至fprintf。 87 00:04:51,920 --> 00:04:54,840 不管特定的功能,我們最終使用,雖然, 88 00:04:54,840 --> 00:04:57,480 所有的人都需要知道,通過他們的觀點, 89 00:04:57,480 --> 00:04:59,670 至少有兩件事情 - 90 00:04:59,670 --> 00:05:03,140 需要寫什麼,它需要被寫入到。 91 00:05:03,140 --> 00:05:07,240 在我們的例子中,輸入的字符串,需要編寫 92 00:05:07,240 --> 00:05:11,290 計劃生育是我們的地方,我們正在編寫的指針。 93 00:05:11,290 --> 00:05:15,330 在這個程序中,第二部分的過程是相當簡單的。 94 00:05:15,330 --> 00:05:17,360 我們只是一個來自用戶的字符串 95 00:05:17,360 --> 00:05:22,120 並直接將其添加到我們的文件,小到沒有輸入驗證或安全檢查。 96 00:05:22,120 --> 00:05:26,160 然而,通常情況下,第二部分將佔用大量的代碼。 97 00:05:26,160 --> 00:05:30,580 最後,第三部分是在第58行,我們關閉文件。 98 00:05:30,580 --> 00:05:34,860 在這裡,我們調用fclose,並通過它我們原來的文件指針。 99 00:05:34,860 --> 00:05:39,500 在隨後的行中,我們返回零,我們的節目結束的信號。 100 00:05:39,500 --> 00:05:42,630 是的,第三部分是那樣簡單。 101 00:05:42,630 --> 00:05:45,260 >> 讓我們從文件讀取。 102 00:05:45,260 --> 00:05:48,220 早在我們的目錄中,我們有一個名為printer.c。 103 00:05:48,220 --> 00:05:50,910 讓我們運行它與我們剛創建的文件 - 104 00:05:50,910 --> 00:05:53,350 doc.txt。 105 00:05:53,350 --> 00:05:58,150 這個程序,顧名思義,會簡單地打印出的文件的內容傳遞給它。 106 00:05:58,150 --> 00:06:00,230 在那裡,我們有它。 107 00:06:00,230 --> 00:06:03,780 該行代碼中,我們輸入了和保存在doc.txt。 108 00:06:03,780 --> 00:06:06,980 你好。我的名字是賈森。 109 00:06:06,980 --> 00:06:09,120 如果我們深入printer.c, 110 00:06:09,120 --> 00:06:13,570 我們看到了很多的代碼看起來類似於我們剛剛走過的typewriter.c。 111 00:06:13,570 --> 00:06:16,720 事實上,第22行,在這裡我們打開的文件, 112 00:06:16,720 --> 00:06:19,220 第39行,我們關閉了文件, 113 00:06:19,220 --> 00:06:23,890 既是幾乎相同的typewriter.c,保存為fopen的第二個參數。 114 00:06:23,890 --> 00:06:26,510 這一次我們從文件中讀取, 115 00:06:26,510 --> 00:06:29,040 因此我們選擇了R替代的W。 116 00:06:29,040 --> 00:06:31,950 因此,讓我們關注的第二個過程的一部分。 117 00:06:31,950 --> 00:06:36,060 在第35行中,在我們的4迴路的第二個條件, 118 00:06:36,060 --> 00:06:38,590 我們對fgets撥打電話, 119 00:06:38,590 --> 00:06:42,190 的伴侶功能從之前到FPUTS。 120 00:06:42,190 --> 00:06:44,660 這一次,我們有三個參數。 121 00:06:44,660 --> 00:06:48,810 首先是指針的數組的字符的字符串將被存儲。 122 00:06:48,810 --> 00:06:52,670 第二個是要讀取的最大字符數。 123 00:06:52,670 --> 00:06:56,010 第三個是我們工作的文件指針。 124 00:06:56,010 --> 00:07:00,780 你會發現,在for循環結束時,與fgets返回null。 125 00:07:00,780 --> 00:07:02,940 有兩個原因,這可能發生。 126 00:07:02,940 --> 00:07:05,380 首先,可能發生錯誤。 127 00:07:05,380 --> 00:07:10,740 其次,更可能的文件,最終達成,並沒有更多的字符讀。 128 00:07:10,740 --> 00:07:14,040 如果你想知道,有兩個功能,使我們能夠告訴 129 00:07:14,040 --> 00:07:17,160 其中的原因是這個特殊的空指針的原因。 130 00:07:17,160 --> 00:07:21,090 而且,這並不奇怪,因為他們所要做的工作的文件, 131 00:07:21,090 --> 00:07:26,940 FERROR功能和的FEOF的功能開始用字母“F”。 132 00:07:26,940 --> 00:07:32,130 >> 最後,在一個快速的注意事項有關的文件的功能,我們可以得出結論, 133 00:07:32,130 --> 00:07:36,690 其中,剛才提到的,寫的是為FEOF。 134 00:07:36,690 --> 00:07:41,550 通常情況下,你會發現自己使用whil​​e和for循環,逐步讀取文件的通過自己的方式。 135 00:07:41,550 --> 00:07:45,790 因此,你需要的方式來結束這些循環後,到達終點這些文件。 136 00:07:45,790 --> 00:07:50,510 ,調用FEOF上的文件指針和檢查,看它是否是真實的 137 00:07:50,510 --> 00:07:52,310 做到這一點。 138 00:07:52,310 --> 00:07:59,820 因此,一個while循環的條件(文件指針(FP))可能看起來像一個完全合適的解決方案。 139 00:07:59,820 --> 00:08:03,770 不過,說我們有一個線留在我們的文本文件。 140 00:08:03,770 --> 00:08:07,130 我們將進入我們的while循環,按計劃,一切都會迎刃而解。 141 00:08:07,130 --> 00:08:12,750 通過下一輪,我們的計劃將檢查,如果FEOF的FP是真正的, 142 00:08:12,750 --> 00:08:15,430 但是 - 這是了解這裡的關鍵點 - 143 00:08:15,430 --> 00:08:17,770 它不會是真實的,只是還沒有。 144 00:08:17,770 --> 00:08:21,110 這是因為是不檢查的目的FEOF 145 00:08:21,110 --> 00:08:24,400 如果讀出功能的下一個呼叫將命中的文件的結尾, 146 00:08:24,400 --> 00:08:28,190 而是,以檢查是否已達到了該文件的結束。 147 00:08:28,190 --> 00:08:30,140 在本實施例的情況下, 148 00:08:30,140 --> 00:08:32,780 閱讀我們的文件的最後一行是完全順利, 149 00:08:32,780 --> 00:08:36,210 但該方案還不知道,我們已經打到最後我們的文件。 150 00:08:36,210 --> 00:08:40,549 這不是一個額外的讀出,直到它,計數器結束的文件。 151 00:08:40,549 --> 00:08:43,210 因此,正確的條件將以下內容: 152 00:08:43,210 --> 00:08:49,330 fgets和它的三個參數 - 輸出,輸出的大小,和FP - 153 00:08:49,330 --> 00:08:52,570 和所有的,不等於空。 154 00:08:52,570 --> 00:08:55,260 這是我們採取的方法在printer.c, 155 00:08:55,260 --> 00:08:57,890 和在這種情況下,循環退出時,後 156 00:08:57,890 --> 00:09:04,290 你可以調用的feof或FERROR退出這個循環的具體理由通知用戶。 157 00:09:04,290 --> 00:09:08,100 >> 寫入和讀取文件,在其最基本的, 158 00:09:08,100 --> 00:09:10,150 三部分組成的一個簡單的過程。 159 00:09:10,150 --> 00:09:12,530 首先,我們打開該文件。 160 00:09:12,530 --> 00:09:16,740 第二,我們把一些東西到我們的文件或採取了一些東西的。 161 00:09:16,740 --> 00:09:19,200 第三,我們關閉該文件。 162 00:09:19,200 --> 00:09:21,170 的第一和最後的部分很容易的。 163 00:09:21,170 --> 00:09:23,920 中間部分是棘手的問題所在。 164 00:09:23,920 --> 00:09:27,760 雖然引擎蓋下的,我們一直在處理一個長序列的零和一, 165 00:09:27,760 --> 00:09:30,710 它添加了一個抽象層編碼時 166 00:09:30,710 --> 00:09:35,350 將序列更接近於我們已經習慣看到的東西。 167 00:09:35,350 --> 00:09:39,570 例如,如果我們正在使用一個24位位圖文件, 168 00:09:39,570 --> 00:09:43,290 我們很可能會被讀​​取或寫入三個字節的時間。 169 00:09:43,290 --> 00:09:46,450 在這種情況下,這將是有意義的定義和適當的命名 170 00:09:46,450 --> 00:09:48,980 一個結構,是3個字節。 171 00:09:48,980 --> 00:09:51,410 >> 雖然工作的文件可能看起來很複雜, 172 00:09:51,410 --> 00:09:54,530 利用它們,可以讓我們做一些真正了不起的。 173 00:09:54,530 --> 00:09:58,880 我們的節目外,我們可以改變世界的狀態, 174 00:09:58,880 --> 00:10:01,730 我們可以創造一些生活以外的生活我們的計劃, 175 00:10:01,730 --> 00:10:07,190 我們之前創建的程序開始運行,甚至可以改變​​的東西。 176 00:10:07,190 --> 00:10:11,210 互動的文件是一個真正強大的部分用C語言編程 177 00:10:11,210 --> 00:10:15,300 我很高興能看到你要創建它的代碼來。 178 00:10:15,300 --> 00:10:19,770 我的名字是賈森·赫塞豪恩。這是CS50。 179 00:10:19,770 --> 00:10:21,770 [CS50.TV] 180 00:10:21,770 --> 00:10:25,940 >> [笑] 181 00:10:25,940 --> 00:10:29,330 好吧。一個需要。在這裡,我們走了。 182 00:10:49,000 --> 00:10:52,140 當我們想到的一個文件 - “”哦,等等。抱歉。 183 00:10:52,140 --> 00:10:56,800 [笑]好吧。 184 00:11:06,620 --> 00:11:09,970 嘿。 185 00:11:13,670 --> 00:11:16,310 當我們想到一個文件 - 186 00:11:17,610 --> 00:11:20,710 當你想到一個文件 - 好。告訴我,當你準備好了。 187 00:11:20,710 --> 00:11:22,520 哦,太棒了。 188 00:11:22,520 --> 00:11:26,180 雖然從提詞器讀取似乎是 - 沒有。我的壞。