学习笔记 day16 系统编程:文件

本文详细介绍了Linux系统中的文件编程,包括系统调用与用户编程接口API的交互,文件描述符的概念以及其在进程中的作用。讨论了Linux中一切皆为文件的哲学,列举了不同类型的文件及其标识,并展示了如何使用系统调用如`open`,`creat`,`read`,`write`和`lseek`进行文件的创建、打开、读写和定位。最后,提供了两个示例,一个是简单的文件拷贝,另一个是向文件写入内容。
摘要由CSDN通过智能技术生成

本地存储

一、文件编程

1、系统调用及用户编程接口(API)

/*
所谓系统调用是指操作系统提供给用户的一组 特殊 接口,用户程序可以通过这组接口获得操作系统内核提供的服务.

由于在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。

每创建一个进程,系统分配4g空间
1g内核使用  3g程序使用
写时复制
*/
image-20230107112206009
/*
用户空间无法直接使用内核空间的数据,只能通过API

系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口。在实际使用中程序员调用的通常是用户编程接口—API
系统命令相对API更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能

*/

2、文件及文件描述符

/*
Linux一点哲学,“一切皆为文件”;在Linux中对目录和设备的操作都等同于对文件的操作;

Linux文件可分为:普通文件,目录文件,链接文件,设备文件;
linux下文件的类型:bsp-lcd
  b:块设备文件
  s:套接字文件
  p:管道文件
  -:普通文件
  l:软链接文件
  c:字符设备文件
  d:目录文件

*/
/*
文件描述符是一个非负的整数,它是一个索引值,并指向内核中每个进程的记录表中;
一个进程启动时,都会打开三个文件:
   标准输入:STDIN_FILENO               0
   标准输出:STDOUT_FILENO              1
   标准出错处理:STDERR_FILENO           2

*/

3、系统调用(不带缓存)文件访问


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//对errno进行分析,#include <errno.h>

int creat(const char *filename, mode_t mode ) 
//creat("main.c",S_IXRWU);
/*
filename:创建的文件名(包含路径,缺省为当前路径)
mode:创建模式
    常用创建模式:USR、OTH、GRP   多个属性用|管道符连接  S_IRUSR|S_IWUSR
        S_IRUSR     可读
        S_IWUSR     可写
        S_IXUSR     可执行
        S_IRWXU     可读、可写、可执行
       除用以上宏来选择创建模式,也可以用数字来表示
返回值:
	成功返回新分配的文件描述符,不可能为0或1
	出错返回-1并设置errno
	
	error的值一般为以下:
        EEXIST 			参数pathname 所指的文件已存在, 却使用了O_CREAT 和O_EXCL 旗标.
        EACCESS 		参数pathname 所指的文件不符合所要求测试的权限.
        EROFS 			欲测试写入权限的文件存在于只读文件系统内.
        EFAULT 			参数pathname 指针超出可存取内存空间.
        EINVAL 			参数mode 不正确.
        ENAMETOOLONG 	参数 pathname 太长.
        ENOTDIR 		参数pathname 不是目录.
        ENOMEM 			核心内存不足.
        ELOOP 			参数pathname 有过多符号连接问题.
        EIO I/O 		存取错误.
*/
int open(const char *pathname,int flags); 
int open(const char *pathname,int flags,mode_t mode); 
/*
pathname:要打开或创建的文件的名字
flags:用来说明此函数的多个选择项
    以下可选项可以同时指定0个或多个, 和必选项按位或起来作为flags参数。
    	O_CREAT 若此文件不存在则创建它。使用此选择项时,需同时说明三个参数mode,用其说明该新文件的存取权限。
    	O_NONBLOCK 如果pathname指的是一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。
    	O_RDONLY 以只读方式打开文件
        O_WRONLY 以只写方式打开文件
        O_RDWR 以可读写方式打开文件. 
        上述三种旗标是互斥的, 也就是不可同时使用, 但可与下列的旗标利用OR(|)运算符组合.
        
        O_EXCL 如果O_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否则将导致打开文件错误. 此外, 若O_CREAT与
        	O_EXCL 同时设置, 并且欲打开的文件为符号连接, 则会打开文件失败.
        	
        O_NOCTTY 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
        O_TRUNC 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为0, 而原来存于该文件的资料也会消失.
        O_APPEND 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面.
        O_NDELAY 同O_NONBLOCK.
        O_SYNC 以同步的方式打开文件.
        O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接, 则会令打开文件失败.
        O_DIRECTORY 如果参数pathname 所指的文件并非为一目录, 则会令打开文件失败。
        
       当O_CREAT|O_WRONLY|O_TRUNC同时作为flag时,此时open相当于creat
    	
    以下三个常数中必须指定一个,且仅允许指定一个(这些常数定义<fcntl.h>头文件中)
        O_RDONLY	只读打开
    	O_WRONLY	只写打开
     	O_RDWR		读、写打开

mode:对于open函数而言,仅当创建新文件时才使用第三个参数
返回值:
	成功返回新分配的文件描述符,不可能为0或1
	出错返回-1并设置errno  /*  https://blog.csdn.net/dp__mcu/article/details/125975488  */
*/

    
int close(int fd);
/*
fd:为open返回的文件描述符      
*/


int read(int fd, const void *buf, size_t length)
/*
//功能:从文件描述符fd所指定的文件中读取length个字节到buf所指向的缓冲区中,返回值为实际读取的字节数。

返回值:	0<=?<=length      当返回值为0时,在网络编程中read读取套接字文件时,返回值为0代表客户机下线

*/
int write(int fd, const void *buf, size_t length)
/*
//功能:把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。
返回值:	只有length=0时,才能返回0,除此之外,write不会返回0


*/
int lseek(int fd, offset_t offset, int whence)
/*
//功能:将文件读写指针相对whence移动offset个字节。操作成功时,返回文件指针相对于文件头的位置

whence可使用下述值:
    SEEK_SET:相对文件开头
    SEEK_CUR:相对文件读写指针的当前位置
    SEEK_END:相对文件末尾
    
offset可取负值,表示向前移动。例如下述调用

返回值:移动的字节数

可将文件指针相对当前位置向前移动5个字节:lseek(fd,-5,SEEK_CUR)

由于lseek函数的返回值为文件指针相对于文件头的位置,因此下面调用的返回值就是文件的长度:lseek(fd,0,SEEK_END)


*/
实例(简单文件拷贝)
//简单文件拷贝
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#define BUFFERSIZE 2

int main(int argc, char const *argv[])
{
    int from_fd,to_fd;
    int bytes_read,bytes_write;
    char buffer[BUFFERSIZE];
    char *ptr=NULL;
    if(argc!=3){
        printf("need from file and to file!\n");
        exit(EXIT_SUCCESS);//0为正常退出   -1为出錯退出
    }
    from_fd=open(argv[1],O_RDONLY);
    if(from_fd==-1){
        perror("open from_file error!");
        exit(EXIT_FAILURE);
    }
    if((to_fd=open(argv[2],O_CREAT|O_WRONLY,0644))==-1){
        perror("open to_file error!");
        close(from_fd);
        exit(EXIT_FAILURE);
    }
    while(bytes_read=read(from_fd,buffer,BUFFERSIZE)){//读取BUFFERSIZE个字节的数据放入缓冲区
        if(-1==bytes_read){
            printf("read error!\n");
            break;
        }
        else if(bytes_read>0){
            ptr=buffer;
            while(bytes_write=write(to_fd,ptr,bytes_read)){//将读取到的实际字节字符串写入文件
                if(-1==bytes_write){
                    perror("write error!");
                    break;
                }
                else if(bytes_write==bytes_read){//此时完全写入
                    break;
                }
                else if(bytes_write>0){//判断不完全写入的情况
                    bytes_read=bytes_read-bytes_write;
                    ptr+=bytes_write;
                }
            }
            if(-1==bytes_write){
                break;
            }
        }
    }
    close(from_fd);
    close(to_fd);
    return 0;
}


//向文件写3个hello
#include <unistd.h>//read write
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>


int main(int argc, char const *argv[])
{
    int fd,i;
    char s[]={"hello"};
    fd=open("3hello.txt",O_CREAT|O_WRONLY,0644);
    if(fd==-1){
        perror("open 3hello.txt error!");
        exit(EXIT_FAILURE);
    }
    for(i=0;i<3;i++){
        write(fd,s,sizeof(s)-1);
        write(fd,"\n",1);
    }
    close(fd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛奶奥利奥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值