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 虽然从提词器读取似乎是 - 没有。我的坏。