Linux系统编程——文件I/O
文件描述符
-
系统调用中操作I/O的函数但是针对文件描述符的
-
文件描述符(file descriptor)通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。
-
文件描述符 0 与 进程的标准输入(standard input)关联
-
文件描述符 1 与 标准输出(standard output)关联
-
文件描述符 2 与 标准错误(standard error)关联
#define STDIN_FILENO 0 //标准输入的文件描述符 #define STDOUT_FILENO 1 //标准输出的文件描述符 #define STDERR_FILENO 2 //标准错误的文件描述符
-
0,1,2对应的物理设备: 键盘,显示器,显示器。
-
文件描述符的作用域仅为当前进程
-
Linux 中一个进程最多只能打开 NR_OPEN_DEFAULT (即1024)个文件
系统调用I/O函数
1.open(打开或创建一个文件)
-
头文件
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
-
函数原型
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); int creat(const char *pathname,mode_t mode);
-
参数:
-
pathname:要打开或创建的文件名称。(含路径,缺省为当前路径)
-
flags:标志位,指定打开文件的操作方式。(前三个常量必须指定且只能指定一个)
flags 解释 O_REONLY 只读方式打开文件 O_WRONLY 可写方式打开文件 O_RDWR 读写方式打开文件 O_CREAT 如果文件不存在时就创建一个新文件,并用第三个参数为其设置权限。 O_EXCL 如果使用O_CREAT 时文件存在,则可返回错误信息。这一参数可测试文件是否存在。 O_NOCTTY 使用本参数时,如文件为终端,那么终端不可以作为调用open ()系统调用的那个进程的控制终端。 O_TRUNC 如文件已经存在,并且以只读或只写成功打开,那么将其长度截短为0。 O_APPEND 以添加方式打开文件,在打开文件的同时,文件指针指向文件末尾。
- mode:指定新文件的访问权限。(仅当创建新文件时才使用该参数)
宏 | 八进制数 | 解释 |
---|---|---|
S_IRWXU | 00700 | 代表该文件所有者具有可读、可写及可执行的权限。 |
S_IRUSR 或S_IREAD | 00400 | 代表该文件所有者具有可读取的权限。 |
S_IWUSR 或S_IWRITE | 00200 | 代表该文件所有者具有可写入的权限。 |
S_IXUSR 或S_IEXEC | 00100 | 代表该文件所有者具有可执行的权限。 |
S_IRWXG | 00070 | 代表该文件用户组具有可读、可写及可执行的权限。 |
S_IRGRP | 00040 | 代表该文件用户组具有可读的权限。 |
S_IWGRP | 00020 | 代表该文件用户组具有可写入的权限。 |
S_IXGRP | 00010 | 代表该文件用户组具有可执行的权限。 |
S_IRWXO | 00007 | 代表其他用户具有可读、可写及可执行的权限。 |
S_IROTH | 00004 | 代表其他用户具有可读的权限。 |
S_IWOTH | 00002 | 代表其他用户具有可写入的权限。 |
S_IXOTH | 00001 | 代表其他用户具有可执行的权限。 |
-
返回值:若成功返回文件描述符,否则返回-1并设置变量errno的值。
-
示例:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main() { int fd = open("./file1",O_RDWR); //打开名为"file1"的文件 if(fd == -1){ printf("open file1 failed\n"); fd = open("./file1",O_RDWR|O_CREAT,0600); //没有此文件则创建,6为可读可写 if(fd > 0){ printf("file1 creat success!\n"); } } close(fd); return 0; }
2.write(把指定数目的数据写入文件)
-
头文件:
#include <unistd.h>
-
函数原型:
ssize_t write(int fd, const void *buf, size_t count);
-
各参数及返回值的含义如下:
-
fd:要写入文件的描述符。
-
buf:要写入的数据。
-
count:要写入数据的字节数。
-
返回值:若成功返回已写的字节数,出错则返回-1并设置变量errno的值。
-
-
size_t是无符号整型,ssize_t是有符号整型
3.read(把指定数目的数据读文件)
-
头文件:
#include <unistd.h>
-
函数原型:
ssize_t read(int fd, void *buf, size_t count);//从文件描述符fd读取count个字节的数据到从buf开始的缓冲区中。
-
各参数及返回值的含义如下:
-
fd:要读取的文件的描述符。
-
buf:读取到的数据放入的缓冲区。
-
count:读取到的字节数。
-
返回值:若成功返回读到的字节数,若已到文件结尾则返回0,若出错则返回-1并设置变量errno的值。
-
4.lseek(移动读、写指针位置)
-
头文件:
#include <sys/types.h> #include <unistd.h>
-
函数原型
off_t lseek(int fildes, off_t offset, int whence);
-
各参数及返回值的含义如下:
-
filder:文件的描述符。
-
offset:offset个字节(可正可负)
-
whence:文件偏移量设置方式
宏 意义 SEEK_SET 将文件偏移量设置在距文件开始处offset个字节 SEEK_CUR 将文件偏移量设置在其当前值加offset个字节 SEEK_END 将文件偏移量设置为文件长度加offset个字节 - 返回值:若成功偏移则返回new file offset,若出错则返回-1并设置变量errno的值。
-
5.close(关闭一个文件描述符)
-
头文件:
#include <unistd.h>
-
函数原型
int close(int fd);
-
fd:要关闭的文件的描述符。
-
返回值:若成功返回0,出错则返回-1。
-
当close关闭动态文件时,close内核将内存中动态文件内容去更新块设备中的静态文件。
小技巧:利用lseek计算文件大小
lseek(fd,0,SEEK_SET);
int filesize = lseek(fd,0,SEEK_END);
printf("file's size is:%d\n",filesize);
函数使用示例
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd;
char* buf = "NB 666 my baby!";
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file1 failed\n");
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd > 0){
printf("file1 creat success!\n");
}
}
printf("open success fd:%d\n",fd);
int n_write = write(fd,buf,strlen(buf));
if (n_write != -1){
printf("write %d Byte to file\n",n_write);
}
lseek(fd,0,SEEK_SET);
char *readBuf = (char*) malloc(sizeof(n_write+1));
int n_read = read(fd,readBuf,n_write);
printf("read:%d byte\n context:%s\n",n_read,readBuf);
close(fd);
return 0;
}
小应用:实现Linux下cp命令
功能:将文件1拷贝到文件2,没有文件2则创建文件2
./mycp src.c des.c
代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char **argv)
{
int fdSrc; //文件1
int fdDes; //文件2
if(argc != 3){ //一共三个参数
printf("pararm error!\n");
exit(-1);
}
fdSrc = open(argv[1],O_RDWR); //打开文件1
if(fdSrc == -1){
printf("no '%s' file\n",argv[1]);
}
lseek(fdSrc,0,SEEK_SET);
int filesize = lseek(fdSrc,0,SEEK_END);//计算文件1大小
lseek(fdSrc,0,SEEK_SET); //将文件1内容读到开辟的buf内
char *readBuf = (char*) malloc(filesize+1);
int n_read = read(fdSrc,readBuf,filesize);
fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600); //将buf内容写入文件2
int n_write = write(fdDes,readBuf,strlen(readBuf));
close(fdSrc);
close(fdDes);
free(readBuf);
return 0;
}