其他章节
第四章 文件和目录
第五章 标准IO
第六章 系统数据文件和信息
第七章 进程环境
第八章
第九章
第十章
提示:个人学习笔记,无参考价值
文章目录
第三章 文件I/O (系统I/O)
1. 文件描述符
类型是整形,是数组的下标,并且文件描述符优先使用数组当前可用范围内最小的下标
2. 文件I/O操作相关函数
open() 与 close()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
//成功返回文件描述符,失败返回-1并设置errno
int open(const char *pathname, int flags, mode_t mode);
#include <unistd.h>
int close(int fd);
参数 flags 必须包含其中一项: O_RDONLY, O_WRONLY, or O_RDWR
。表示只读,只写和可读可写。
另外,多个文件的创造模式和状态模式一起并起来赋给flags。文件创造模式有O_CLOEXEC,O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE和O_TRUNC。文件状态模式有 O_APPEND, O_ASYNC和O_CREAT等等。
例如: r -> O_RDONLY
r+ -> O_RDWR
w -> O_WRONLY | O_CREAT | O_TRUNC(只可写,无则创建,有则覆盖)
w+ -> O_RDWR | O_CREAT | O_TRUNC (可读可写,无则创建,有则覆盖)
【详解】
open函数一般用于打开或者创建文件,在打开或创建文件时可以制定文件的属性及用户的权限等各种参数。
第一个参数path表示:路径名或者文件名。路径名为绝对路径名(如C:/cpp/a.cpp),文件则是在当前工作目录下的。
第二个参数oflags表示:打开文件所采取的动作。可能值:必须指定下面某一种:
O_RDONLY(只读),
O_WRONLY(只写),
O_RDWR(可读可写)
打开/创建文件时,至少得使用上述三个常量中的一个,以下常量是选用的:
O_APPEND 每次写操作都写入文件的末尾
O_CREAT 如果指定文件不存在,则创建这个文件
O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改errno的值
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)
第三个参数mode表示:设置文件访问权限的初始值。(与用户掩码umask变量有关,实际的访问权限有mode &~umask确定)
S_IRUSR, S_IWUSER, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH.
其中S_I:前缀,R:读,W:写,X:执行,USR:文件所属的用户,GRP:文件所属的组,OTH:其他用户。
【注】第三个参数是在第二个参数中有O_CREAT时才用作用。若没有,则第三个参数可以忽略。
返回值:如果操作成功,它将返回一个文件描述符,如果失败,返回-1
read() write() lseek()
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//whence的取值:SEEK_SET SEEK_CUR 或 SEEK_END
-
read
参数buf:存储读取的内容
参数count:指定想要读取的字节个数
返回值:成功返回真正读取到的字节数(0代表文件读到末尾);失败返回-1并设置errno -
write
参数buf:存储要写入的内容
参数count:指定想要写入的字节个数
返回值:成功返回真正写入的字节数;失败返回-1并设置errno -
lseek
成功返回文件开头到当前位置的偏移量,失败返回-1并设置errno。
相当于fseek和ftell的结合
案例 复制文件
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 1024
int main(int argc, char *argv[]){
if (argc < 3){
fprintf(stderr,"usage: %s srcfile destfile\n",argv[0]);
exit(1);
}
int fds,fdd;
char buf[BUFSIZE];
int len,ret,pos;
fds = open(argv[1], O_RDWR);
if (fds < 0){
perror("open(srcfile)");
exit(1);
}
fdd = open(argv[2], O_WRONLY|O_CREAT,O_TRUNC,777);
if (fdd < 0){
perror("open(destfile)");
close(fds);
exit(1);
}
while (true){
len = read(fds,buf,BUFSIZE);
if (len < 0){
perror("read(fds)");
break;
}
if (len == 0){
break;
}
pos = 0;
//ret有可能不等于len,即len个字节没有完全写完
while (len > 0){
ret = write(fdd,buf+pos, len);
if (ret < 0){
perror("write(fdd)");
exit(1);
}
pos += ret;
len -= ret;
}
}
close(fdd);
close(fds);
exit(0);
}
3. 文件IO与标准IO的区别
- 系统IO操作文件时是无缓冲输入,一般用于操作字符设备文件(LCD, LED, BEEP …,数据需要实时刷新)标准IO操作文件时是有缓冲输入,一般用于操作普通文件(.txt, .jpg…)
- 系统IO是Linux操作系统提供函数接口,标准IO标准C语言库函数提供的。标准IO是对系统IO的包装,在标准IO的实现中,实际上调用系统IO提供的函数。
- 系统IO响应速度快,而标准IO吞吐量大
【注意】文件IO与标准IO不可以混用
比较示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
putchar('1');
write(1,"a",1);
putchar('2');
write(1,"b",1);
putchar('3');
write(1,"c",1);
//输出结果:abc123
exit(0);
}
因为 putchar是标准io函数,具有缓冲区,而write是系统io函数,没有缓存区,直接输出,所以会先输出abc。等运行到exit(0)时,会刷新缓存区,输出123。
4. 原子操作
不可分割的操作。作用:解决竞争和冲突
5. dup() 与 dup2()
先看一个案例,完成输出重定向,代码如下:
#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(){
close(1);
int fp = open("./dup.txt",O_RDWR|O_CREAT|O_TRUNC|0600);
if (fp < 0){
perror("open()");
exit(0);
}
puts("hello");
exit(0);
}
close(1);关闭了标准输出流,fp由open创建,是当前可用的最小整数,即1。 上述代码将puts()的输出,由标准输出流改成fp。即输出到文件./dop.txt中。
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
-
dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符oldfd指向相同的文件、管道或者网络连接。并且dup返回的文件描述符总是取系统当前可用的最小整数值。
#include<stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> int main(){ int fd = open("./dup.txt",O_RDWR|O_CREAT|O_TRUNC|0600); if (fd < 0){ perror("open()"); exit(1); } close(1); int newFd = dup(fd); //复制fd文件描述符, close(fd); //close(newFd); puts("hello"); exit(0); }
//往dup.txt写入hello
-
dup2()函数,完成的功能与dup一样。当newfd被占用时,会先关闭该文件描述符,再将oldfd复制一份,放在newfd中。当oldfd与newfd相等,则函数直接返回newfd,没有关闭操作。
#include<stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> int main(){ int fd = open("./dup.txt",O_RDWR|O_CREAT|O_TRUNC|0600); if (fd < 0){ perror("open()"); exit(1); } //close(1); //int newFd = dup(fd); //复制fd文件描述符, dup2(fd,1); //是原子操作,完成上面两句代码的功能 if (fd != 1) close(fd); puts("hello"); exit(0); }
6. fcntl() 与ioctl()
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl()针对(文件)描述符提供控制。参数fd是被参数cmd操作(如下面的描述)的描述符。针对cmd的值,fcntl能够接受第三个参数int arg。
fcntl()的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列命令有特定返回值:F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN。
F_DUPFD 返回新的文件描述符
F_GETFD 返回相应标志
F_GETFL , F_GETOWN 返回一个正的进程ID或负的进程组ID
fcntl函数有5种功能:
- 复制一个现有的描述符(cmd=F_DUPFD).
- 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
- 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
- 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
- 获得/设置记录锁(cmd=F_GETLK , F_SETLK或F_SETLKW).
补充:str类函数族
strlen
功 能: 返回字符串长度。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char * str = "123";
printf("strlen = %ld\n", strlen(str)); //3
exit(0);
}
stpcpy
功 能: 拷贝一个字符串到另一个
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char * str1 = "shahao";
char str2[10];
strcpy(str2,str1);
printf("%s\n",str2);
exit(0);
}
strcat
功 能: 字符串拼接函数
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
char str1[10] = "shahao";
char * str2 = "kaikai";
strcat(str1,str2);
printf("%s\n",str1);
exit(0);
}
strcmp
功 能: 看Asic码,str1>str2,返回值 > 0;两串相等,返回0
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
char * str1 = "shaohao";
char * str2 = "shihao";
if (strcmp(str1,str2) > 0){
printf("str1 = %s \n",str1);
} else if (strcmp(str1,str2) < 0){
printf("str2 = %s \n",str2);
} else{
printf("str1 == str2\n");
}
exit(0);
}
//输出结果:shihao
strchr
功能为查找str中首次出现c的位置,如有有,则返回出现位置,否则返回NULL。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char * str = "shahaoshihao";
char * c = strchr(str,'a');
printf("%c\n",*c); //a
printf("%s\n",c); //ahaoshihao
exit(0);
}
strrchr
功能为查找str中最后一次出现c的位置,如有有,则返回出现位置,否则返回NULL。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char * str = "shahaoshihao";
char * c = strrchr(str,'a');
printf("%c\n",*c); //a
printf("%s\n",c); //ao
exit(0);
}
strstr
功能为查找字符串str2在str1中出现的位置,找到则返回位置,否则返回NULL 。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char * str = "shahaoshiha---sshihao123";
char * c = "shihao";
char * str1 = strstr(str,c);
printf("%c\n",*str1); //s
printf("%s\n",str1); //shihao123
exit(0);
}