赵老师笔记----系统调用IO
一、什么是系统编程
有操作系统的环境下编程,并使用操作系统提供的系统调用及各种库,对系统资源进行访问
二、什么是系统调用?
1.系统调用很重要,它是介于内核和应用程序的中间的桥梁。
2.系统调用是操作系统提供给用户程序的一组“特殊”函数接口。
3.用户程序可以通过这组接口获得操作系统(内核)提供的服务。
三、系统调用的分类
进程控制、进程间通信、文件系统控制、系统控制、内存管理、网络管理、socket控制、用户管理。
四、系统调用,函数接口的返回值
系统调用的返回值: 通常,用一个负的返回值来表明错误,返回一个0值表明成功。错误信息存放在全局变量errno中,用户可用perror函数打印出错信息。
perror("open");
open: .....
五、系统调用文件I/O
open、close、write 、read、fcntl、dup、dup2
1.文件描述符
是操作系统标识文件的标志,它是一个非负的整数,最小值是0,最大值1024
2.默认打开的文件标识符
0 STDIN_FILENO stdin 标准输入,默认就是终端键盘
1 STDOUT_FILENO stdout 标准输出,默认是终端屏幕
2 STDERR_FILENO stderr 标准错误
3.Linux操作系统下,一切皆文件
六、常用系统调用文件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);
pathname:文件的路径及文件名。
flags:open函数的行为标志。
mode:文件权限(可读、可写、可执行)的设置。
user group others 八进制的数表示r、w、x
返回值:
成功返回打开的文件描述符。
失败返回-1,可以利用perror去查看原因
2.close函数:关闭一个文件
#include <unistd.h>
int close(int fd);
参数:
fd是调用open打开文件返回的文件描述符。
返回值:
成功返回0。
失败返回-1,可以利用perror去查看原因。
举例
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
fd=open("test",O_WRONLY|O_CREAT,744);
if (fd<0)
{
perror("open");
return -1;
}
close(fd);
return 0;
}
3.write函数:把指定数目的数据写到文件
#include <unistd.h>
ssize_t write(int fd, const void *addr,size_t count);
参数:
fd:文件描述符。
addr:数据首地址。
count:写入数据的字节个数。
返回值:
成功返回实际写入数据的字节个数。
失败返回-1,可以利用perror去查看原因。
4.read函数:把指定数目的数据读到内存
#include <unistd.h>
ssize_t read(int fd, void *addr, size_t count);
参数:
fd:文件描述符。
addr:内存首地址。
count:读取的字节个数。
返回值:
成功返回实际读取到的字节个数。
失败返回-1,可以利用perror去查看原因。
举例1:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define SIZE 30
int main()
{
int fd;
int ret;
char buf[SIZE]="I love c programing!";
fd=open("test",O_WRONLY|O_CREAT,777);
if (fd<0)
{
perror("open");
return -1;
}
ret=write(fd,buf,sizeof(buf));
if (ret<0)
{
perror("write");
return -1;
}
close(fd);
fd=open("test",O_RDONLY);
if (fd<0)
{
perror("open");
return -1;
}
bzero(buf,SIZE);
ret=read(fd,buf,SIZE);
if (ret<0)
{
perror("read");
close(fd);
return -1;
}
else
{
if (ret==0)
{
close(fd);
return 0;
}
else
{
printf("%s,char sum =%d",buf,ret);
}
}
close(fd);
return 0;
}
举例2:从read标准输入输入字符,再用write输出到标准输出。当输入是“quit”时退出。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 30
int main()
{
int ret;
char buf[SIZE];
while (1)
{
bzero(buf,SIZE);
if (ret=read(0,buf,SIZE)<0)
{
perror("read failed");
exit(1);
}
else if(ret==0||strncmp(buf,"quit",4)==0)
break;
else
write(1,buf,ret);
}
return 0;
}
5.remove库函数:删除文件
#include <stdio.h>
int remove(const char *pathname);
参数:
pathname :文件的路名+文件名。
返回值:
成功返回0。
失败返回-1,可以利用perror去查看原因。
6.文件描述符的复制
dup和dup2是两个非常有用的系统调用,都是用来复制一个文件的描述符,使新的文件描述符也标识旧的文件描述符所标识的文件。
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup和dup2经常用来重定向进程的stdin、stdout和stderr。
#include <unistd.h>
int dup(int oldfd);
功能:
复制oldfd文件描述符,并分配一个新的文件描述符,新的文件描述符是调用进程文件描述符表中最小可用的文件描述符。
参数:要复制的文件描述符oldfd。
返回值:
成功:新文件描述符。
失败:返回-1,错误代码存于errno中
#include <fcntl.h>
int main(void)
{
int fd1;
int fd2;
fd1 = open("test", O_CREAT|O_WRONLY, S_IRWXU);
if (fd1 < 0)
{
perror("open");
exit(-1);
}
close(1);
fd2 = dup(fd1);
printf("fd2=%d\n", fd2);
return 0;
}
dup2函数
#include <unistd.h>
int dup2(int oldfd, int newfd)
功能:
复制一份打开的文件描述符oldfd,并分配新的文件描述符newfd,newfd也标识oldfd所标识的文件。
注意:
newfd是小于文件描述符最大允许值的非负整数,如果newfd是一个已经打开的文件描述符,则首先关闭该文件,然后再复制。
参数:
要复制的文件描述符oldfd
分配的新的文件描述符newfd
返回值:
成功:返回newfd
失败:返回-1,错误代码存于errno中
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1;
int fd2 = 3;
int err = 0;
err = dup2(1,fd2);//save 1
if(err<0)
{
perror("dup2");
}
printf("fd2=%d,err=%d\n", fd2, err);
fd1 = open("test", O_CREAT|O_RDWR, S_IRWXU);
dup2(fd1,1);//1---> test
printf("hello world\n");
dup2(fd2,1);//reset 1--->stdout
printf("I love you \n");
return 0;
}
7.lseek函数
#include <sys/types.h>
off_t lseek( int fd, off_t offset, int origin );
origin
名称 说明
SEEK_SET 从文件的开始处开始搜索
SEEK_CUR 从当前位置开始搜索
SEEK_END 从文件的结束处开始搜索
练习答案:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
if((argc == 3) && (strcmp(argv[1], argv[2]) != 0))
{
int fd_src, fd_dest, ret;
fd_src = open(argv[1], O_RDONLY);
if(fd_src < 0)
{
perror("open argv[1]");
return -1;
}
fd_dest = open(argv[2], O_WRONLY|O_CREAT, 0755);
if(fd_dest < 0)
{
close(fd_src);
perror("open argv[2]");
return -1;
}
do
{
char buf[1024] = "";
ret = read(fd_src, buf, sizeof(buf));
write(fd_dest, buf, ret);
}while(ret > 0);
close(fd_src);
close(fd_dest);
}
return 0;
}