今天学习了读写文件函数的相关知识,参考的书籍是周立功写的《嵌入式Linux开发教程(上册)》,第11.3节。
1. open函数和creat函数
因为creat函数可以用open函数来实现,所以就不再去理会它了。关于open函数,记忆起来可以拆解成几点:
A)有int型返回值,返回的是所打开文件的句柄,或者称为文件描述符。
B)第一个参数是字符型指针,用来传递所要打开的文件名,通常的做法有两种:可以创建一个字符型数组,将文件名存入数组,再把数组名当成第一个参数;也可以直接把文件名字符串当成第一个参数。
C)第二个参数是限定以什么方式打开文件,包括只读,只写等等,具体配置的方法请查看参数解释。
D)第三个参数是当open函数用作创建新文件时,设定文件的权限。参数如下:
之所以把这个表格粘贴出来,是为了说明我在写测试程序时所遇到的问题:
看上去每个参数既可以写符号常量,也可以写对应的数值。但当我使用数值来指定文件权限时,发现创建的文件权限根本不对。经过反复尝试,最终发现不能使用数值,而要使用符号常量。我对此事的解释是,写教材的人所用的open函数可能与我的open函数在底层实现方法上有差异。那么,相同的符号常量,对应的数值可能就变了。
通过这件事也给我一个提醒,在调取这些标准库函数时,参数尽量使用符号常量,不要图省事写数值。这可能导致程序的可移植性变差。
2. 关于文件的权限,再补充一些知识点:
A)linux对于新建文件一般都有一个默认的权限,是由umask数值来决定的。umask在命令行中是一条指令,输入就可以查看系统的umask值。
B)umask的数值一般是4位的,比如我的系统查的umask值为0002。它怎么理解呢?不看最左边的那个0。剩下的002应该理解成 --- --- -w-
C)没错,umask就是文件权限的数字简写。最左边三个字符代表文件所属用户的操作权限;中间三个字符代表与文件所属用户在同一个用户组的其他用户的操作权限;最右边三个字符代表其他用户的操作权限。
D)不过,umask所代表的权限,指的是新创建文件不应该具备的属性。也就是说,虽然当前系统的umask数值翻译过来是:只有其他用户具备对文件写操作的权限。但是新建的文件,却恰好要剥夺这个权限。
E)更重要的是,umask对新文件默认权限的限制会与open函数创建新文件时所指定的权限共通决定新文件的权限。具体执行逻辑可以这样理解:open函数指定新文件的权限,然后再根据umask的值砍掉其中的一些。
F)为了让open函数可以完全指定新文件的权限,可以在程序中预先使用umask()函数指定umask的数值。
G)暂时不知道umask函数在哪个头文件中声明的,因此我在调用该函数时,编译报警了,但不影响使用。
3. 关于write函数
关于write函数,记忆起来可以拆解成几点:
A)有一个有符号整型的返回值,代表实际写入的字符数,如果出错了则返回-1。
B)第一个参数是文件句柄(或者称为文件描述符),这与前面open函数的返回值是一回事。显然,你要对一个文件进行写操作,必须知道要操作的文件是谁。而执行open函数的一个效果,就是获取打开文件的句柄。这个句柄拿来给write函数使用,逻辑上顺理成章。
C)第二个参数是任意类型的数据指针,指向的是一个缓冲区的首地址。这个缓冲区里面预先放好打算写入文件的数据。也有两种写法,可以先创建一个字符型数字,然后将数组名用作参数;也可以直接把待写入文件的字符串用作参数;这与open函数的第一个参数用法类似。
D)第三个参数是无符号整型数据,代表的是将要写入文件的数据字节数。
4. 使用write函数中遇到的问题
A)我创建了一个名为text的字符型容量不限的数组,并且给它赋值:text[]=”abc”;在填写第三个参数时,使用sizeof函数。
B)操作过后,用vi编辑器查看,发现被写入文件的字符是:abc^@
用gedit查看文件,会提示有乱码:
C)我认为多写入文件的那个字符是‘\0’,因为系统会自动在字符串的结尾加上‘\0’作为结束标识。这个转义字符也会占用一个字节,当使用sizeof函数来统计字符串长度时,会把它也算在内。
D)为了验证这个想法,我将write函数的第三个参数人为指定成3,这样果然就一切正常了。
E)至于vi中显示的那个^@符号,在网上查了下,有人指出它就是代表‘\0’。
F)书中指出,实际写入的字符数可以少于指定的字符数,我不太明白何时会出现这种情况?
随便做了个小测试,将写入的字符数人为指定成10个。执行程序后,用vi打开file1.txt,看到这么个东西:
看来,至少我这种尝试并不会让实际写入文本的数据少于指定的值。这个问题悬而未决。。。。
5. 由一个疑问引发的测试及其结果
用write函数写入数据的时候,如果一次没写完,接下来想继续写怎么办?会不会把原先的内容覆盖掉?换言之,操作系统怎么知道从文件的什么地方开始写数据?
A)我猜测,系统会有某种机制记忆写入数据的起点。逻辑应该是,当第一次打开文件时,默认以最开头的位置为起点。当写过一次后,只要不关闭文件,那么下次再写入会接着上次结束的位置继续写
B)为了验证这想法,我先打开文件,然后写入abc,紧接着又写入def。完事后查看文件,果然就成了abcdef
C)再来一个实验,这次是先打开文件,然后写入abc,关闭文件。再打开文件,然后写入def。完事后查看文件,果然就成了def。相当于覆盖了abc
D)最后一个实验,先打开文件,然后写入abc(使用第一次打开文件时获得的句柄),不关闭文件的情况下再用open打开一次文件,然后写入def(使用第二次打开文件时获得的句柄)。查看文件后,发现内容是def
E)这让我突然对open函数连续打开同一个文件产生了兴趣。暂时没有深入研究,只是做了两个测试。
其一,打开一个文件,然后不关闭再打开一次。发现两次的文件句柄不同。
其二,打开一个文件,关闭后再打开,发现两次文件句柄相同。
这让我感觉,句柄是临时分配的。
6. 最后贴上今天写的测试代码
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
int fd=-1;
int fd1=-1;
int res=0;
char buf1[]="abc";
char buf2[]="def";
// umask(0000);
/**************************第一次打开文件,并且写入abc,然后关闭*******************************/
fd = open("file1.txt", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
if (fd < 0)
printf("create file failed!\n");
else
{
printf("create file success!\n");
printf("file 's fd is %d\n",fd);
}
res = write(fd, buf1, 3);
if (res < 0)
printf("write text into file failed!\n");
else
printf("write %d bytes into file1.txt\n",res);
close(fd);
/**************************第二次打开文件,并且写入def,然后关闭*******************************/
fd1 = open("file1.txt", O_RDWR);
if (fd1 < 0)
printf("open file failed!\n");
else
{
printf("open file success!\n");
printf("file 's fd is %d\n",fd1);
}
res = write(fd1, buf2, 3);
if (res < 0)
printf("write text into file failed!\n");
else
printf("write %d bytes into file1.txt\n",res);
close(fd1);
return 0;
}