文件扩展名
在linux中,扩展名对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系统中把一切都看做文件,Linux有7中类型文件:普通文件-、目录(dierectory)文件、符号(link)链接、字符
(character)设备文件、块(block)设备文件、管道(pipe)文件、套接字(socket)文件。其中文件、目录、符号链接会占用磁盘
空间来存储,而块设备、字符设备、套接字、管道是伪文件,并不占用磁盘空间。
文件类型标识 | 文件类型 |
- | 普通文件 |
d | 目录文件 |
l | 符号链接 |
c | 字符设备 |
b | 块设备 |
p | 管道 |
s | 套接字socket |
linux命令行中,我们通过ls -l命令可以查看文件的相应类型
文件描述符
文件描述符(file descriptor fd)是Liunx内核为了高限管理已被打开的文件所创建的的索引,是一个非负数(通常是小整数),用于指代被打开的文件,所有I/O操作的系统调用都通过文件描述符。程序在开始运行时,系统会自动打开三个文件描述符,0是标准输入,1是标准输出,2是标准出错。POSIX标准要求每打开文时(含socket)必须使用当前进化成那个中最小可用的文件描述符号码,因此第一次打开的文件描述符一定是3。
文件描述符 | 用途 | POSIX文件描述符 | 标准I/o文件流 |
0 | 标准输入 | STDIN_FILENO | stdin |
1 | 标准输出 | STDOUT_FILENO | stdout |
2 | 标准出错 | STDERR_FILENO | stderr |
我们可以通过代码理解下
#define STR "Hello World\n"
int main(int main, char *argv[])
{
printf("%s", STR);
fputs(STR, stdout);
write(STDOUT_FILENO, STR, strlen(MSG_STR));
return 0;
}
编译输出后
Hello World
Hello World
Hello World
文件I/O操作函数
open()系统调用
int open(const char *path, int oflag, ... /*mode_t mode*/);
open()系统调用用来打开一个文件,并返回一个文件描述符(file description), 并且该文件描述符是当前进程最小、未使用的
文件描述符数值。
参数: path: 要打开的文件、设备的路径
oflag: 由多个选项进行“或”运算构造oflag参数 。
必选: O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写)
可选: O_APPEND 每次写时都追加到文件的尾端。
O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode
O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作
设置非阻塞模式方式。
O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY....
mode: oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如066。 否则不
需要。使用示例代码:
int fd;
fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
fd = open(“text.txt”, O_WRONLY|O_APPEND);
create()系统调用
int creat(const char *path, mode_t mode);
此函数用来创建一个新文件并返回其fd。它等价于 open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
int fd;
fd=creat(“text.txt”, 0644);
close()系统调用
int close(int fd);
该函数用来关闭一个打开的文件描述符,关闭一个文件时还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,
内核将会自动关闭它所有打开的文件。
write()系统调用
ssize_t write(int fd, const void *buf, size_t nbytes);
write()函数用来往打开的文件描述符fd指向的文件中写入buf指向的数据,其中nbytes指定要写入的数据大小。如果返回值
<0则说明写入出错,譬如尝试往一个只读的文件中写入则会抛错,错误的原因系统会保存到errno变量中去。如果>0则为实
际写入的数据大小。
read()系统调用
ssize_t read(int fd, void *buf, size_t nbytes);
read()函数用来从打开的文件描述符对应的文件中读取数据放到buf指向的内存空间中去,最多不要超过nbytes个字节,这里
的nbytes一般是buf剩余的空间大小。如read成功,则返回实际读到的字节数(由nbytes或读到文件尾决定,其中EOF宏用
来判断是否到了文件尾),如果返回值小于0则表示出错,如尝试读一个没有权限读的文件时就会抛错。
文件I/O操作
我们通过一段程序,并通过注释来理解
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //程序包含的头文件
#define BUFSIZE 1024 //定义了一个整数常量
#define MSG_STR "Hello World\n" //定义了一个字符串常量 保存到程序的只读数据段中(Rodata)
int main(int argc, char *argv[])
{
int fd = -1; //定义fd,用来接收文件描述符
int rv = -1;
char buf[BUFSIZE]; //定义一个长度为BUF_SIZE的字符数组
fd=open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);//调用 open()系统调用并返回一个文件描述符保存在fd中,如果fd<0则说明文件打开失败了。
if(fd < 0)
{
printf("Open/Create file test.txt failure");
return 0;
}
printf("Open file returned file descriptor [%d]\n", fd);// 调试打印一下fd返回的文件描述符,如果程序运行异常,我们经常会在程序中加入printf来调试错误,这是程序出错调试最常用的方法;
if( (rv=write(fd, MSG_STR, strlen(MSG_STR))) < 0 ) //调用write()系统调用将字符串“Hello World\n”的内容写入到文件中去,函数调用如果出错则返回-1,这
时我们打印相应的错误原因;
{
printf("Write %d bytes into file failure: %s\n", rv, strerror(errno));
goto cleanup;
}
if( (rv=read(fd, buf, sizeof(buf))) < 0 )//这里我们调用read()系统调用,从文件中读取内容放入到buf中去,如果出错则打印出错的信息。当然在程序运行结果中我们发现并没有读到数据,接下来我们会分析其中原因;
{
printf("Read data from file failure\n");
goto cleanup;
}
printf("Read %d bytes data from file: %s\n", rv, buf);
cleanup:
close(fd);
return 0;
}