目的:其实在Linux下文件是否可以执行与文件拓展名没有太大关系。但是,我们添加这种扩展名可以进行人为的区分,以便后面的有效分类以及使用。
扩展名 | 表示 | 扩展名 | 表示 |
---|---|---|---|
.tar, .tar.gz, .tgz, .zip, .tar.bz | 表示压缩文件,创建命令为tar, gzip, unzip等 | .sh | 表示shell脚本文件 |
.pl | 表示perl语言文件 | .py | 表示python语言文件 |
.conf | 表示系统服务的配置文件 | .c | 表示C文件 |
.h | 头文件 | .cpp | 表示C++源文件 |
.so | 表示动态库文件 | .a | 表示静态库文件 |
Linux下有7种类型文件(可以通过ls -l命令查看):
文件类型标识 | 文件类型 |
---|---|
- | 普通文件 |
d(dierectory) | 目录文件 |
l (link) | 符号链接 |
c(character) | 字符设备 |
b(block) | 块设备 |
p (pipe) | 管道 |
s(socket) | 套接字 |
文件描述符:内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符(0是标准输入,1是标准输出,2是标准错误)。所有执行I/O操作的系统调用都通过文件描述符。(来源:百度百科)
文件描述符的优点:
基于文件描述符的I/O操作兼容POSIX标准。
在UNIX、Linux的系统调用中,大量的系统调用都是依赖于文件描述符。
文件描述符 | 用途 | POSIX文件描述符 | 标准I/O文件流 |
---|---|---|---|
0 | 标准输入 | STDIN_FILENO | stdin |
1 | 标准输出 | STDOUT_FILENO | stdout |
2 | 标准出错 | STDERR_FILENO | stderr |
例如:现在我想将stdout.c文件中的hello world打印到屏幕上去
#include //printf在该头文件中声明
#include //STDOUT_FILENO, stdout等在该头文件中声明
#include //strlen在该头文件中声明,具体参考man strlen
#define MSG_STR "Hello World\n"
int main(int main, char *argv[]) //argc是命令行总的参数个数,argv[]是argc个参数
{
printf("%s", MSG_STR);
fputs(MSG_STR, stdout); //fputs→ouput of characters and strings
write(STDOUT_FILENO, MSG_STR, strlen(MSG_STR)); //write→send amessage to another user
return 0;
}
gcc stdout.c -o stdout //转换成可执行文件
./stdout //执行stdout文件
得到:
那么fputs和write在这里起什么作用呢?
接下里我们将fput和write的代码段删掉
#include //printf在该头文件中声明
#define MSG_STR "Hello World\n"
int main(int main, char *argv[])
{
printf("%s", MSG_STR);
return 0;
}
执行后得到:
总结:其实我们可以发现printf和fputs和write所表现的功能是一样的,都是“Hello world!"输出到屏幕上。但是,我们发现所用的参数不一样。就像fputs→标准I/O文件流。write→POSIX文件描述符。
(不带缓存)文件I/O操作:打开文件、读文件、写文件、关闭文件等,对应用到的函数有:open、read、write、close、lseek(文件指针偏移)
不带缓存:每一个函数都只调用系统中的一个函数。
来源:https://www.cnblogs.com/wurenzhong/p/7500867.html
open()系统调用:用来打开一个文件,并返回一个文件描述符(file description), 并且该文件描述符是当前进程最小、未使用的文件描述符数值。
int open(const char *path,int oflag,.../*mode_t mode*/); //路径、输出模式、(文件权限)
参数 | 功能 |
---|---|
path | 要打开的文件、设备的路径 |
oflag | 必选:O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写) |
oflag | 常用可选:O_APPEND 每次写时都追加到文件的尾端 |
oflag | 常用可选:O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode(必须带该参数用来指定创建文件的权限模式) |
oflag | 常用可选:O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0; |
oflag | 常用可选:O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作设置非阻塞模式方式。 |
示例代码:
int fd;
if(fd=open("/sys/bus/w1/devices/28-041731f7c0ff/w1_slave",O_RDWR|O_CREAT|O_TRUNC, 0666)<0);
返回值:
等于0:若所有欲核查的权限都通过了检查。
小于0:只要有一个权限被禁止。
create ()系统调用:用来创建一个新文件并返回其fd。
int creat(const char *path, mode_t mode); //路径、权限
示例代码:
fd=creat("....",0666)
close()系统调用:用来关闭一个打开的文件描述符,会返回fd。
int close (int fd);
write()系统调用:用来往打开的文件描述符fd指向的文件中写入buf指向的数据,其中nbytes指定要写入的数据大小。
ssize_t write(int fd,const void *buf, size_t nbytes);
返回值(一般与nbytes相同):
大于0:返回nbytes数据大小。
小于0:出错(写操作错误,还有死循环等)。
read()系统调用:从打开的文件描述符对应的文件中读取数据放到buf指向的内存空间中去。
ssize_t read(int fd, void *buf, size_t nbytes);
返回值:
大于0:返回实际读到的字节数。
小于0:出错。
lseek()系统调用:从文件里读出内容,或往文件写如内容的时候都有一个起始地址,这个起始地址就是当前文件偏移量,当我们对文件
进行读写的时候都会使文件偏移量往后偏移。
off_t lseek(int fd, off_t offset, int whence);
whence | 光标位置 |
---|---|
SEEK_SET | 文件头 |
SEEK_CUR | 当前位置 |
SEEK_END | 文件尾 |
dup() 和 dup2()系统调用:复制一个新文件描述符来指向fd对应文件。
dup() | dup2() |
---|---|
int dup(int fd) | int dup2(int fd,int fd2) |
返回新文件描述符(最小数值) | 可以用fd2参数来指定新文件描述符 |
dup2用法:
比如1本身没有什么意义,但是我们可以用数字1来映射一种信息。比如说1就代表人,2代表牛,3代表羊。当我们使用dup2后。我现在不让3代表羊了,让3代表人。那么我之前所有和3说话的函数,就不再是和羊说话,而改为和人说话了。同理,1的背后就是stdout,如果我们dup2(fileFd, 1)。那么1的背后就不再是标准输出(指显示器设备),而变为了fileFd背后的文件。我们的printf == fprintf(stdout, …) ,那些所有原来向stdout输出的函数,他们只知道向stdout输出,但stdout的背后被我们修改了,他们是不知道的。简单来说,就是我们修改了映射关系。(转自:网友答复)
stat()和fstat()系统调用:返回文件/目录的相关信息。
stat() | fstat() |
---|---|
int stat(const char * restrict path, struct stat *restrict buf); | int fstat(int fd, struct stat *buf); |
返回新文件描述符(最小数值) | 可以用fd2参数来指定新文件描述符 |
access()系统调用:测试文件存在/权限。
int access(const char *path, int mode); //路径 模式
模式 | 说明 | 模式 | 说明 |
---|---|---|---|
R_OK | 测试读许可权 | W_OK | 测试写许可权 |
X_OK | 测试执行许可权 | F_OK | 测试文件是否存在 |
unlink()系统调用:删除文件(path指定的文件的链接数减1。当链接数为0时,文件内容被删除)。
rename()系统调用:文件重命名。
int rename(const char *oldname, const char *newname);
通过例子了解文件I/O操作
例如:我现在有一个w1_slave文件(放置温度监测的温度读数),现在我想要编写file_io.c文件去读取w1_slave文件里面存放的温度数据。
t=14500就是现在的温度(当然,真实的温度是14.5°。所以后面编写代码的时候,我们要/1000)。
因为:在实际工作中,存放w1_slave文件的28-041731f7c0ff文件夹。文件夹名字中的28-后面的序列号会变化,但是28-不会变化。
所以:我们在这里进行了寻找w1_slave文件的操作。
gcc ds18b20.c -o ds18b20
./ds18b20