Linux
- 1、文件IO
- 1.1、open and close
- 1.2、read and write
- 1.3、lseek
- 1.4、综合练习
- 2、目录IO
- 2.1、mkdir
- 2.2、opendir, closedir, readdir
- 2.3、综合练习
1、文件IO
1.1、open and close
使用以下代码查看以下open函数原型:
man 2 open
如图,open函数有两个原型,分别是:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
其中
pathname:文件所在的路径。
flag:文件给用户的权限。
mode:对新创建的文件赋予的权限。
返回值:一个文件描述符,以整数的形式体现,成功打开则返回3,4,5其中一个,失败则返回-1。
flag的参数有以下这些,可以用" | "(或逻辑)同时选择多个。当选择到O_CREAT的时候,必须添加第三个参数mode。下面这些参数具体意义还得查看手册(manual)。
必选:O_RDONLY, O_WRONLY, O_RDWR
可选:O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE
mode参数一般是四位数,第一位数表示八进制(不管它,输入0即可)。后面三位数分别表示用户权限,同组用户权限,其他用户权限。用rwx表示权限,然后1/0表示是否开启该权限,最后将其组合转化为八进制。如下:
rwx: read write execute
111(rwx)->7,110(rw-)->6....(二进制转换)
0000(000 000 000: --- --- ---)
0001(000 000 001: --- --- --x)
0002(000 000 010: --- --- -wx)
...
0777(111 111 111: rwx rwx rwx)
但所创建的文件真实的权限还要和umask码取反后相与,可以输入umask查看其具体值:
最后是close函数,就相对非常简单多了。把open返回的文件描述符号作为输入参数即可。
close(fd);
note: fd is a file descriptor
1.2、read and write
先查看以下函数原型:
man 2 read
如图,其函数原型是:
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符。
*buf:指向读取的内容的指针 。
count:要读取的字节数 。
返回值:如果读取成功,则返回读取的字节数目。如果失败,返回-1;如果正常读取,但没读取到东西,返回0。
再来看看write函数。依旧先看manual。
man 2 write
函数原型是:
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符。
*buf:指向写入缓冲区的内容的指针 。
count:要写入的字节数 。
返回值:如果写入成功,则返回写入的字节数目。如果失败,返回-1;如果正常写入,但没写入任何东西,则返回0。
注意的地方:
- 如果write的第一个参数是为1,则意为把缓冲区的东西写入终端,而非写入文件。
1.3、lseek
老生常谈,先看一些它的函数说明。
man 2 lseek
可以看出,其函数原型是;
off_t lseek(int fd, off_t offset, int whence);
fd:文件描述符。
offset:指针偏移的量 。
whence:指针偏移的基准位置。(可选的参数有:SEEK_SET, SEEK_CUR, SEEK_END…)
返回值:如果写入成功,则返回所指向的字节数。如果失败,则返回-1。
这里有几个点需要说明:
- 无论是ssize_t,还是off_t之类的,其实都属于整形数据。所以在一般情况下,把他们当整形用即可。
- 文件的读写操作都是依靠指针的偏移来确定位置的。譬如当你读完或写完N个字节,该指针也会随之偏移到第N位去,直到文件被close指针才复位。
- 默认打开文件的时候,文件指针指向定0个字节。
1.4、综合练习
- 练习任务:
- 在“/home/yuquan”下创建并打开一个test.c文件
- 往该文件写入“writing successfully!”的字符串
- 将该字符串读取并打印出来。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
char buf_read[21] = {0};
int fd = open("/home/yuquan/test.c",O_RDWR|O_CREAT, 0777);
write(fd, "writing successfully!\n", 22);
lseek(fd,-22,SEEK_CUR); //让指针从新指向文件开头
read(fd, buf_read, 21);
printf("the string you read is:%s\n",buf_read);
close(fd);
return 0;
}
上面这段代码去掉了很多检查报错冗余代码,一般来说不建议这样写,而是像下面这样写好些。
2、目录IO
2.1、mkdir
查看函数说明:
man 2 mkdir
可以看到函数原型是:
int mkdir(const char *pathname, mode_t mode);
*pathname:将被创建的文件所在的目录。
mode:给该文件的权限,参考文件IO小节的open中的mode,原理是一样的。
返回值:成功返回0,失败返回-1。
2.2、opendir, closedir, readdir
opendir的函数说明在manual第三页,所以应该输入以下指令来查找。
man 3 opendir
可以看到函数原型有两个,分别是:
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
name:文件的名称(包含路径)。
fd:文件的描述符,配合文件IO中的open函数使用。
返回值:如果正确打开文件,则返回一个文件流指针,反之返回NULL。
文件流指针是一个指向文件的指针,在初始时刻,它指向的是打开该文件夹之后的第一个文件。
接着,再来看看closedir函数:
man 3 closedir
DIR *dirp:目录流指针。
返回值:成功返回0,失败返回-1。
最后说一下readdir
man 3 readdir
函数原型是:
struct dirent *readdir(DIR *drip);
DIR * dirp:文件流指针。
返回值:成功读取返回一个结构体,失败返回NULL。
readdir函数读完一个文件之后,文件流指针会接着往下偏移,直到该文件夹里的所有文件被读取完毕且返回NULL。接着细说一下这个结构体,从使用手册可以看出它的结构长这样:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
比较重要的参数有以下两个,其中的d_ino指的是文件的编号,比如我输入ls -i之后看到的数字:
d_name[256]指的是所读文件的名称,比如下面这些:
2.3、综合练习
- 练习任务:
- j键盘输入一个目录,并且将该目录中的所有文件都打印到终端里来。
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int mian(int argc, char *argv[])
{
struct dirent *temp;
if(argc != 2)
{
printf("using:%s <directory name>\n",argv[0]);
}
DIR *drip = opendir(argv[1]);
int i = 0;
while((temp=readdir(dirp)) != NULL)
{
i++;
printf("the %d file name is: %s \n",i,temp->d_name);
}
return 0;
}
注意:遍历文件只能有一个层级,不能遍历文件中的文件。因为文件流指针只指向该文件的下一层级。