Linux系统文件操作

Linux系统编程

一.文件编程/文件操作/IO流?

1.操作API

// C语言中需要包含几个文件操作的头文件
#include <sys/types.h>
#include <sys/stat.j>
#include <fcntl.h>
函数原型 touch 文件名.属性 // 创建文件?
open原型

open 打开 // 没有这个文件会直接创建这个文件

返回值是一个整型 *重要文件描述符

pathname    // 文件名(或者要打开的文件的路径)
flags       // 操作权限 O_RDONLY只读  O_WRONLY只写  O_RDWR可读可写
int main()
{
    int fd; // 创建一个文件描述符变量  也可以叫句柄  其他几个函数来操作句柄
    /*open函数返回一个负数就表示打开文件操作失败,返回一个非0正整数则表示打开成功*/
    fd = open("./file1",O_RDWR);    // 当前路径下的file1文件,可读可写方式打开
    printf("fd:%d\n",fd);
    if(fd < 0){ // 打开失败
        printf("open is file1 failed!\n");
        /*重新打开文件,如果文件存在则直接打开该文件,不存在就直接新建一个文件.打开和创建是或的关系|*/
        // 可读4  可写2 执行1
        fd = open("./file1",O_RDWR|O_CREAT,0600);   // 0600是6(4+2)是操作用户可读可写,十位0是同组其他用户权限,各位0是其他组用户权限
        if(fd > 0){
            printf("file1 created successfully!\n");
        }
    }
    printf("fd:%d\n",fd);
    
    return 0;
}

ls -l   // 查询该目录下文件的权限

参数说明
int open(const char *pathname, ,int flags);
int open(const char *pathname, int flags, mode_t mode);
Pathname:要打开的文件名(含路径,缺省为当前路径)
Flags:
O_RDONLY 只读打开   O_WRONLY 只写打开   O_RDWR 可读可写打开
当我们附带了权限后,打开的文件就只能按照这种权限来操作。
以上这三个常数中应当只指定一个。
下列常数是可选择的:
O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode. 用其说明该新文件的存取许可权限。
O_ExCL 如果同时指定了O_CREAT,而文件已经存在,则出错。
O_APPEND 每次与时都加到文件的尾端。
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。
Mode:一定是在flags中使用了O_CREAT标志,mode 记录待创建的文件的访问权限
creat创建文件
       #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);
​
       int openat(int dirfd, const char *pathname, int flags);
       int openat(int dirfd, const char *pathname, int flags, mode_t mode);
​
pathname**要创建的文件名(包含路径,缺省为当前路径)
mode**创建模式  // 可读可写可执行  7
一般用第三个原型创建文件
write原型

write 写入

ssize_t write(int fd, const void *buf, size_t count);

#include <unistd.h> // 要用write函数就需要包含这个头文件
​
ssize_t write(int fd, const void *buf, size_t count);
/*
fd:句柄   open函数返回值   文件标识符
buf:无类型的指针(例如:字符串*char)
count:写入文件的大小(字符串的长度)*字节
返回值是一个整型数
*/
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <stdio.h>
#include <unistd.h>     // write函数头文件
#include <string.h>     // 字符串操作头文件
​
int main()
{
    int fd; // 创建一个文件描述符变量  也可以叫句柄  其他几个函数来操作句柄
    /*open函数返回一个负数就表示打开文件操作失败,返回一个非0正整数则表示打开成功*/
    fd = open("./file2",O_RDWR);    // 当前路径下的file1文件,可读可写方式打开
    printf("fd:%d\n",fd);
    if(fd < 0){ // 打开失败
        printf("open is file2 failed!\n");
        /*重新打开文件,如果文件存在则直接打开该文件,不存在就直接新建一个文件.打开和创建是或的关系|*/
        // 可读4  可写2 执行1
        fd = open("./file2",O_RDWR|O_CREAT,0600);   // 0600是6(4+2)是操作用户可读可写,十位0是同组其他用户权限,各位0是其他组用户权限
        if(fd > 0){
            printf("file2 created successfully!\n");
        }
    }
    printf("open succcessfully file2 fd:%d\n",fd);
    
    char *buf = "I am nianxing_Su!";        // 写入的内容
    int n_write = write(fd,buf,strlen(buf));    // fd句柄,文件标识符   buf写入内容     strlen(buf)写入文件的大小  //strlen计算字符串的长度
    if(n_write > 0){
        printf("write file1 successfully!*number:%d\n",n_write);
    }else{
        printf("write file1 failed!\n");
    }
    close(fd);  // 关闭文件,类似释放内存资源操作
}

read原型

read 读取

ssize_t read(int fd, void *buf, size_t count);

#include <unistd.h>     // 包含头文件
​
ssize_t read(int fd, void *buf, size_t count);
// fd文件标识符      
// buf读取内容存放区(缓存区)  
// count读取字节数(整数,可以是其他整数)
​
​
    char *readBuf;  // 定义缓存区
    readBuf = (char *)malloc(sizeof(char) * n_write + 1);   // 给缓存区分配空间(大小)
    int n_read = read(fd,readBuf,n_write);  // fd文件标识符      readBuf读取内容存放区(缓存区) n_write读取字节数(整数)
    printf("rad:%d,text:%s\n",n_read,readBuf);      // 读取内容是重光标位置往后读取,所有需要先移动光标到要开始读取的内容前
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <stdio.h>
#include <unistd.h>     // write,read函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
​
int main()
{
    int fd; // 创建一个文件描述符变量  也可以叫句柄  其他几个函数来操作句柄
    /*open函数返回一个负数就表示打开文件操作失败,返回一个非0正整数则表示打开成功*/
    fd = open("./file1",O_RDWR);    // 当前路径下的file1文件,可读可写方式打开
    printf("fd:%d\n",fd);
    if(fd < 0){ // 打开失败
        printf("open is file1 failed!\n");
        /*重新打开文件,如果文件存在则直接打开该文件,不存在就直接新建一个文件.打开和创建是或的关系|*/
        // 可读4  可写2 执行1
        fd = open("./file1",O_RDWR|O_CREAT,0600);   // 0600是6(4+2)是操作用户可读可写,十位0是同组其他用户权限,各位0是其他组用户权限
        if(fd > 0){
            printf("file1 created successfully!\n");
        }
    }
    printf("open successfully file1 fd:%d\n",fd);
    
    char *buf = "I am nianxing_Su!";        // 写入的内容
    int n_write = write(fd,buf,strlen(buf));    // fd句柄,文件标识符   buf写入内容     strlen(buf)写入文件的大小  //strlen计算字符串的长度
    if(n_write > 0){
        printf("write file1 successfully!*number:%d\n",n_write);
    }else{
        printf("write file1 failed!\n");
    }
    close(fd);  // 先关闭
    
    fd = open("./file1",O_RDWR);    // 再打开文件,   光标就会再文件头部
    
    char *readBuf;  // 定义缓存区
    readBuf = (char *)malloc(sizeof(char) * n_write + 1);   // 给缓存区分配空间(大小)
    int n_read = read(fd,readBuf,n_write);  // fd文件标识符      readBuf读取内容存放区(缓存区) n_write读取字节数(整数可写其他整数)
    printf("read successfully:%d,text:%s\n",n_read,readBuf);        // 读取内容是重光标位置往后读取,所有需要先移动光标到要开始读取的内容前
    close(fd);  // 关闭文件,类似释放内存资源操作
    return 0;
}
lseek原型

lseek 光标定位 // 移动光标?

#include <sys/types.h>  // 头文件
#include <unistd.h>     // 头文件
​
off_t lseek(int fd, off_t offset, int whence);  
// 返回的是一个相对文件头部的偏移字节数,错误则返回-1
// fd句柄,文件标识符
// offset偏移值    相对光标位置的偏移   负数往前移动,正数往后移动
// whence相对起始位置
/*
SEEK_SET    文件头部
    The file offset is set to offset bytes.
​
SEEK_CUR    光标当前位置
    The file offset is set to its current location plus offset bytes.
​
SEEK_END    文件尾部
    The file offset is set to the size of the file plus offset bytes.
*/
#include <sys/types.h>  // open,lseek函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <stdio.h>
#include <unistd.h>     // write,read,close,lseek函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
​
int main()
{
    int fd; // 创建一个文件描述符变量  也可以叫句柄  其他几个函数来操作句柄
    /*open函数返回一个负数就表示打开文件操作失败,返回一个非0正整数则表示打开成功*/
    fd = open("./file1",O_RDWR);    // 当前路径下的file1文件,可读可写方式打开
    printf("fd:%d\n",fd);
    if(fd < 0){ // 打开失败
        printf("open is file1 failed!\n");
        /*重新打开文件,如果文件存在则直接打开该文件,不存在就直接新建一个文件.打开和创建是或的关系|*/
        // 可读4  可写2 执行1
        fd = open("./file1",O_RDWR|O_CREAT,0600);   // 0600是6(4+2)是操作用户可读可写,十位0是同组其他用户权限,各位0是其他组用户权限
        if(fd > 0){
            printf("file1 created successfully!\n");
        }
    }
    printf("open successfully file1 fd:%d\n",fd);
    
    char *buf = "I am nianxing_Su!";        // 写入的内容
    int n_write = write(fd,buf,strlen(buf));    // fd句柄,文件标识符   buf写入内容     strlen(buf)写入文件的大小  //strlen计算字符串的长度
    if(n_write > 0){
        printf("write file1 successfully!*number:%d\n",n_write);
    }else{
        printf("write file1 failed!\n");
    }
    
    // lseek(fd,1,SEEK_SET);    // 光标在头部位置向后偏移一个字节
    // lseek(fd,-1,SEEK_CUR);   // 光标在原有位置向前偏移一个字节
    // lseek(fd,-17,SEEK_END);  // 光标在尾部位置向前偏移17个字节
    int filesize = lseek(fd,-n_write,SEEK_END); // 光标在尾部位置向前偏移n_write个字节
    
    printf("%d\n",filesize);    // 返回的是一个相对文件头部的偏移字节数,错误则返回-1
    char *readBuf;  // 定义缓存区
    readBuf = (char *)malloc(sizeof(char) * n_write + 1);   // 给缓存区分配空间(大小)
    int n_read = read(fd,readBuf,n_write);  // fd文件标识符      readBuf读取内容存放区(缓存区) n_write读取字节数(整数可写其他整数)
    printf("read successfully:%d,text:%s\n",n_read,readBuf);        // 读取内容是重光标位置往后读取,所有需要先移动光标到要开始读取的内容前
    close(fd);  // 关闭文件,类似释放内存资源操作
    return 0;
}

close原型

close 关闭

#include <unistd.h>     // 头文件
​
int close(int fd);      
// 就是open打开文件的返回句柄,文件标识符,传入给close函数关闭那个打开的文件即可

创建文件夹
mkdir   IO  // 当前目录下创建一个IO文件夹
mkdir home/nianxing_su/syh/IO1  // 在home/nianxing_su/syh这个路径下创建一个IO1文件夹
打开文件/创建文件补充知识
参数说明
int open(const char *pathname, ,int flags);
int open(const char *pathname, int flags, mode_t mode);
Pathname:要打开的文件名(含路径,缺省为当前路径)
Flags:
O_RDONLY 只读打开   O_WRONLY 只写打开   O_RDWR 可读可写打开
当我们附带了权限后,打开的文件就只能按照这种权限来操作。
以上这三个常数中应当只指定一个。
下列常数是可选择的:
O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode. 用其说明该新文件的存取许可权限。
O_ExCL 如果同时指定了O_CREAT,而文件已经存在,则出错。
O_APPEND 每次与时都加到文件的尾端。
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。
Mode:一定是在flags中使用了O_CREAT标志,mode 记录待创建的文件的访问权限
#include <sys/types.h>  // open,lseek函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <stdio.h>
#include <unistd.h>     // write,read,close,lseek函数头文件
#include <string.h>     // 字符串操作头文件
​
​
int main()
{
    int fd;
    fd = open("./file2",O_RDWR,0600);   // 以读写权限打开一个file2文件 每次打开文件光标默认位置在头部
    if(fd == -1){
        printf("%d\n",fd);
        printf("open is file2 failed!\n");  // 如果返回值为-1,则说明打开失败,成功就返回一个正整数
    }
    close(fd);
    
    fd = open("./file2",O_RDWR|O_CREAT,0600);   // 以读写权限打开一个file2文件,如果file2文件不存在则创建file2文件
    if(fd > 0){
        printf("%d\n",fd);
        printf("file2 created successfully!\n");    // 如果返回值为-1,则说明打开失败,成功就返回一个正整数
    }
    close(fd);
    
    fd = open("./file2",O_RDWR|O_CREAT|O_EXCL,0600);    // 以读写权限打开一个file2文件,如果file2文件不存在则创建file2文件,如果file2文件存在则出错返回-1
    if(fd == -1){
        printf("%d\n",fd);
        printf("this file2 exists!\n"); // 如果返回值为-1,则说明打开失败,成功就返回一个正整数
    }
    close(fd);
    
    fd = open("./file1",O_RDWR|O_APPEND,0600);  // 每次写入操作都在文件末尾写入
    char *str = "123456789";    // 写入内容
    int n_write = write(fd,str,strlen(str));    // 返回写入了多少个字节
    close(fd);
    
    fd = open("./file1",O_RDWR|O_TRUNC,0600);   // 把文件原始数据清空,重起始位置写入数据(打开文件并清空数据)
    char *str1 = "abcdefghijklmnopqrstuvwxyz";  // 写入内容
    n_write = write(fd,str1,strlen(str1));  // 返回写入了多少个字节
​
    
    close(fd);  // 关闭文件,类似释放内存资源操作
    return 0;
}
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
​
int creat(const char *pathname, mode_t mode);
​
pathname**要创建的文件名(包含路径,缺省为当前路径)
mode**创建模式  // 可读可写可执行  7
    // S_IRUSR  4   可读
    // S_IWUSR  2   可写
    // S_IXUSR  1   可执行
    // S_IRWXU  7   可读可写可执行
    
#include <sys/types.h>  // open,lseek函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <stdio.h>
#include <unistd.h>     // write,read,close,lseek函数头文件
#include <string.h>     // 字符串操作头文件
​
​
int main()
{
    int fd;
    fd = creat("/home/nianxing_su/syh/syh",7);  
    close(fd);
    
    fd = creat("/home/nianxing_su/syh/syh1",S_IRWXU);   // 文件名及其路径  权限
    // S_IRUSR  4   可读
    // S_IWUSR  2   可写
    // S_IXUSR  1   可执行
    // S_IRWXU  7   可读可写可执行
    
    close(fd);  // 关闭文件,类似释放内存资源操作
    return 0;
}
其他

pwd // 查询绝对路径

文件描述符:
1、对于内核而言,所有打开文件都中文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和writen。
按照惯例,UNIX shell使用文件描达符0与进程的标准输入相结合,文件描达符1与桥准输出相结合,文件描述符2与标准錯误输出相结合。STDIN_FILENO, STDOUT_FILENO, STDERR_FILEND这几个宏代巷了0-1-2这几个数。
2、文件描述符,这个数宇在一个进程中表示一个特定含义,当我们open一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数宇就和我们内存中维护的这个动态文件的这些数据结构绑上了,以后我们应用程序如果要操作这个动态文件,只需要用这个文件描述符区分。
3,文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1
#include <sys/types.h>  // open,lseek函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <stdio.h>
#include <unistd.h>     // write,read,close,lseek函数头文件
#include <string.h>     // 字符串操作头文件
​
​
int main()
{
    char readBuf[128];
    
    int n_read = read(0, readBuf, 5);   // 从标准输入中读取5个字节存入readBuf    键盘输入5个字节
    
    int n_write = write(1, readBuf, strlen(readBuf));   // 把readBuf的数据写入标准输出中   刚刚键盘输入的数据打印一次
    
    printf("\ndome\n");     // 换行
    return 0;
}
​
打开/创建文件->读取文件/写入文件->关闭文件
打开/创建文件->读取文件/写入文件->关闭文件
1、在inux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后是close关闭文件即可。
2、强调一点:我们对文件进行操作时,一定要先打开文件,打开成功之后才能操作,如果打开失败,就不用进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏。
3、文件平时是存放在块设备中的文件系统文件中的,我们把这种文件叫静态文件,当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(叫动态文件)。
4、打开文件以后,以后对这个文件的读写操作,都是针对内存中的这一份动态文件的,而并不是针对静态文件的。当然我们对动态文件进行读写以后,此时内存中动态文件和块设备文件中的靜态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步) 块设备中的静态文件。
5、为什么这么设计,不直接对块设备直接操作。
块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。

用户操作->内核响应->内核调用驱动去磁盘映射出来->或者调用驱动执行

小技巧
cp xmian.c ymain.c  // 复制xmian.c文件并重命名新文件ymian.c
vimdiff xmian.c ymain.c     // 同时打开两个文件     按方向右键

思路:
1.打开拷贝源文件xmian.c
int fd = open("xmain.c",O_RDWR);
2.读取xmian.c的所有内容到buf
char *buf;
// buf = (char *)malloc(sizeof(char) * n_write + 1);    // 是否需要开辟空间
read(fd,buf,size);  // size长度
3.打开/创建新文件ymain.c
int fd1 = open("ymain.c",O_RDWR);
4.向新文件写入buf数据
write(fd,buf,strlen(buf));  
5.关闭两个文件
close(fd);
close(fd1);

复制格式会出问题

int size = lseek(fdsrc,0,SEEK_END); // 计算文件字节大小

#include <stdio.h>
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <unistd.h>     // write,read,close函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
#include <stdlib.h>     // malloc函数的头文件
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    
    // if(argc < 3){
    if(argc != 3){
        return argc;    // 参数不满足3个时,直接结束程序返回参数个数
    }
    
    int fdsrc;
    
    char *readbuf = NULL;       // 缓存区
    
    
    fdsrc = open(argv[1],O_RDWR);       // 打开源文件    源文件时肯定存在的
    int size = lseek(fdsrc,0,SEEK_END); // 计算字节大小
    lseek(fdsrc,0,SEEK_SET);    // 移动光标到头部
    
    readbuf = (char *)malloc(sizeof(char) * size + 8);  // 动态开辟空间
    
    int n_read = read(fdsrc,readbuf,size);  // 读取源文件的数据 
    
    // int fddes = open(argv[2],O_RDWR|O_CREAT,0600);       // 创建新的文件   权限可读可写
    int fddes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);      // 如果文件本身存在而且内容很多,打开后清空内容再写入数据
    int n_write = write(fddes,readbuf,strlen(readbuf));     // 写入数据
    
    close(fdsrc);   // 关闭
    close(fddes);   // 关闭
    return 0;
}
​

main函数原型

cp xmian.c ymain.c

参数1 程序名 cp 参数2xmian.c 参数3 ymian.c

#include <stdio.h>
​
​
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    printf("totol params:%d\n",argc);
    printf("no.1 params:%s\n",argv[0]);
    printf("no.2 params:%s\n",argv[1]);
    printf("no.3 params:%s\n",argv[2]);
    printf("no.4 params:%s\n",argv[3]);
    return 0;
}

修改配置文件
1.找到字符串的起始位置
2.计算字符串的长度  偏移量
3.修改字符串 移动光标到头部或者打开方式使用O_TRUNC
cat text.config     // 打印文本内容

#include <stdio.h>
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <unistd.h>     // write,read,close函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
#include <stdlib.h>     // malloc函数的头文件
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    
​
    if(argc != 2){
        printf("The parameyer does not meet the conditions.exit\n");
        exit(-1);   // 退出程序?
        // return argc; // 参数不满足2个时,直接结束程序返回参数个数
    }
    
    int fdsrc;
    
    char *readbuf = NULL;       // 缓存区
    
    
    fdsrc = open(argv[1],O_RDWR);       // 打开源文件    源文件时肯定存在的
    if(fdsrc == -1){    // 判断文件是否打开成功
        printf("File opening failure.exit\n");
        exit(-1);
    }
    int size = lseek(fdsrc,0,SEEK_END); // 计算字 节大小
    lseek(fdsrc,0,SEEK_SET);    // 移动光标到头部
    
    readbuf = (char *)malloc(sizeof(char) * size + 8);  // 动态开辟空间
    
    int n_read = read(fdsrc,readbuf,size);  // 读取源文件的数据 
    if(n_read == -1){   // 判断数据是否读取成功
        printf("Data read failure.exit\n");
        exit(-1);
    }
    
    close(fdsrc);   // 关闭
    
    char *p = NULL;
    p = strstr(readbuf,"LENG = ");  // 查找子字符串,返回一个指针,子字符串的起始位置指针
    if(p == NULL){  // 没找到就退出程序
        printf("Not found.exit\n");
        exit(-1);
    }
    p = p + strlen("LENG = ");  // 指针偏移到要修改数据的位置    // 可以定义一个变量来存储,或者用传参的方式
    *p = 'S';   // 单个字符
    p = p + 1;  // 指向下一个字符的位置   p++也可以
    *p = 'Y';   // 单个字符
    p = p + 1;  // 指向下一个字符的位置   p++也可以
    *p = 'H';   // 单个字符
    fdsrc = open(argv[1],O_RDWR|O_TRUNC,0600);      // 如果文件本身存在而且内容很多,打开后清空内容再写入数据,要么就移动光标
    if(fdsrc == -1){    // 判断文件是否打开成功
        printf("File opening failure.exit\n");
        exit(-1);
    }
    
    int n_write = write(fdsrc,readbuf,strlen(readbuf));     // 写入数据
    if(n_read == -1){   // 判断数据是否读取成功
        printf("Data write failure.exit\n");
        exit(-1);
    }
    
    
    close(fdsrc);   // 关闭
    
    return 0;
}
​
文件写入数字
#include <stdio.h>
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <unistd.h>     // write,read,close函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
#include <stdlib.h>     // malloc函数的头文件
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    
​
    if(argc != 2){
        printf("The parameyer does not meet the conditions.exit\n");
        exit(-1);   // 退出程序?
        // return argc; // 参数不满足2个时,直接结束程序返回参数个数
    }
    
    int fdsrc;
    int data1 = 100;
    int data2 = 0;
    printf("data2:%d\n",data2);
    fdsrc = open(argv[1],O_RDWR|O_TRUNC);       // 打开源文件    源文件时肯定存在的
​
    int n_write = write(fdsrc,&data1,sizeof(int));  // 写入一个整型数
    
    lseek(fdsrc,0,SEEK_SET);    // 移动光标到头部
    
    int n_read = read(fdsrc,&data2,sizeof(int));    // 读取一个整形给data2
    
    printf("data2:%d\n",data2);
    close(fdsrc);   // 关闭
    
    return 0;
}
写入读取结构体
#include <stdio.h>
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <unistd.h>     // write,read,close函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
#include <stdlib.h>     // malloc函数的头文件
​
struct Test
{
    int num;
    char sex;
};
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    
​
    if(argc != 2){
        printf("The parameyer does not meet the conditions.exit\n");
        exit(-1);   // 退出程序?
        // return argc; // 参数不满足2个时,直接结束程序返回参数个数
    }
    
    int fdsrc;
    struct Test data1 = {100,'g'};
    struct Test data2;
    // data2 = NULL;
    printf("num:%d\tsex:%c\n",data2.num,data2.sex);
    fdsrc = open(argv[1],O_RDWR|O_TRUNC);       // 打开源文件    源文件时肯定存在的   清空源文件
​
    int n_write = write(fdsrc,&data1,sizeof(struct Test));  // 写入一个整型数
    
    lseek(fdsrc,0,SEEK_SET);    // 移动光标到头部
    
    int n_read = read(fdsrc,&data2,sizeof(struct Test));    // 读取一个整形给data2
    
    printf("num:%d\tsex:%c\n",data2.num,data2.sex);
    
    close(fdsrc);   // 关闭
    
    return 0;
}
写入读取一个数组结构体
#include <stdio.h>
#include <sys/types.h>  // open函数头文件
#include <sys/stat.h>   // open函数头文件
#include <sys/fcntl.h>  // open函数头文件
#include <unistd.h>     // write,read,close函数头文件
#include <string.h>     // 字符串操作头文件
#include <stdlib.h>     // malloc函数的头文件
#include <stdlib.h>     // malloc函数的头文件
​
struct Test
{
    int num;
    char sex;
};
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    
​
    if(argc != 2){
        printf("The parameyer does not meet the conditions.exit\n");
        exit(-1);   // 退出程序?
        // return argc; // 参数不满足2个时,直接结束程序返回参数个数
    }
    
    int fdsrc;
    struct Test data1[2] = {{100,'g'},{101,'m'}};
    struct Test data2[2];
​
    fdsrc = open(argv[1],O_RDWR|O_TRUNC);       // 打开源文件    源文件时肯定存在的   清空源文件
​
    int n_write = write(fdsrc,&data1,sizeof(struct Test)*2);    // 写入一个整型数
    
    lseek(fdsrc,0,SEEK_SET);    // 移动光标到头部
    
    int n_read = read(fdsrc,&data2,sizeof(struct Test)*2);  // 读取一个整形给data2
    
    printf("num:%d\tsex:%c\n",data2[0].num,data2[0].sex);
    printf("num:%d\tsex:%c\n",data2[1].num,data2[1].sex);
    
    close(fdsrc);   // 关闭
    
    return 0;
}
写入读取链表
标准C库的文件操作
***标准C库与Linux系统的区别

1. 来源
从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:
​
open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。 
 PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。
 
2. 移植性
这一点从上面的来源就可以推断出来,`fopen`是C标准函数,因此拥有良好的移植性;而`open`是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数`CreateFile`。
​
 
3. 适用范围
open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
fopen是用来操纵普通正规文件(Regular File)的。
 
4. 文件IO层次
如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。
​
 
5. 缓冲
缓冲文件系统 
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
非缓冲文件系统 
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。
一句话总结一下,就是open无缓冲,fopen有缓冲。前者与read, write等配合使用, 后者与fread,fwrite等配合使用。
​
使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:read,write);而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。
函数原型C 标准库 – | 菜鸟教程 (runoob.com)

读写的次数是根据对应函数的第三个参数来的,读是写多少就是多少,写是根据实际次数

fopen()函数原型
#include <stdio.h>
​
FILE *fopen(const char *pathname, const char *mode);
​
FILE *fdopen(int fd, const char *mode);
​
FILE *freopen(const char *pathname, const char *mode, FILE *stream);
// 函数原型上面的时原型
​
/*      打开模式
       r      Open text file for reading.  The stream is positioned at  the  be‐
              ginning of the file.
​
       r+     Open for reading and writing.  The stream is positioned at the be‐
              ginning of the file.
​
       w      Truncate file to zero length or create text file for writing.  The
              stream is positioned at the beginning of the file.
​
       w+     Open  for reading and writing.  The file is created if it does not
              exist, otherwise it is truncated.  The stream is positioned at the
              beginning of the file.
​
       a      Open  for appending (writing at end of file).  The file is created
              if it does not exist.  The stream is positioned at the end of  the
              file.
​
       a+     Open for reading and appending (writing at end of file).  The file
              is created if it does not exist.  Output is always appended to the
              end  of  the file.  POSIX is silent on what the initial read posi‐
              tion is when using this mode.  For glibc, the initial  file  posi‐
              tion  for  reading  is  at  the beginning of the file, but for An‐
              droid/BSD/MacOS, the initial file position for reading is  at  the
              end of the file.
*/
​
/*
mode 打开模式
r   只读方式打开一个文本文件
rb  只读方式打开一个二迸制文件
w   只写方式打开一个文本文件
wb  只写方式打开一个二迸制文件
a   追加方式打开一个文本文件
ab  追加方式打开一个二进制文件
r+  可读可写方式打开一个文本文件
rb+ 可读可写方式打开一个二进制文件
w+  可读可写方式创建一个文本文件
wb+ 可读可写方式生成一个二进制文件
a+  可读可写追加方式打开一个文本文件
ab+ 可读可写追加一个二进制文件
*/
fwrite()函数原型
#include <stdio.h>
​
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
​
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
​
​
fread()函数原型
#include <stdio.h>
​
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
​
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
​
​
fclose()函数原型
#include <stdio.h>
​
int fclose(FILE *stream);
​
fseek()函数原型
#include <stdio.h>
​
int fseek(FILE *stream, long offset, int whence);
​
long ftell(FILE *stream);
​
void rewind(FILE *stream);
​
int fgetpos(FILE *stream, fpos_t *pos);
​
int fsetpos(FILE *stream, const fpos_t *pos);
​
​
The  fseek()  function  sets  the  file position indicator for the stream
pointed to by stream.  The new position, measured in bytes,  is  obtained
by adding offset bytes to the position specified by whence.  If whence is
set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset  is  relative  to  the
start  of  the  file, the current position indicator, or end-of-file, re‐
spectively.  A successful call to the fseek() function clears the end-of-
file  indicator  for  the  stream and undoes any effects of the ungetc(3)
function on the same stream.
实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
​
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    FILE *fp;
    char *str = "I am name nianxing_su.";
    char *readbuf;
    readbuf = (char *)malloc(sizeof(char)*strlen(str)+1);
    fp = fopen("./syh.txt","w+");       // 路径当前文件夹下的syh.txt文件   打开模式w+,如果文件不存在则直接创建该文件
    
    fwrite(str,sizeof(char),strlen(str),fp);    // 写入数据
    // fwrite(str,sizeof(char)*strlen(str),1,fp);
    
    fseek(fp,0,SEEK_SET);   // 移动光标到头部
    
    fread(readbuf,sizeof(char)*strlen(str),1,fp);   // 读取数据
    
    fclose(fp);     // 关闭
    
    printf("%s\n",readbuf);
    return 0;
}
标准C库读写结构体
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
​
struct Test
{
    int num;
    char sex;
};
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    FILE *fp;
​
    struct Test data1 = {100,'g'};
    struct Test data2;
    // data2 = NULL;
    printf("num:%d\tsex:%c\n",data2.num,data2.sex);
    fp = fopen("./file","w+");      // 打开源文件    源文件时肯定存在的   清空源文件
​
    int n_write = fwrite(&data1,sizeof(struct Test),1,fp);  // 写入一个整型数
    
    fseek(fp,0,SEEK_SET);   // 移动光标到头部
    
    int n_read = fread(&data2,sizeof(struct Test),1,fp);;   // 读取一个整形给data2
    
    printf("num:%d\tsex:%c\n",data2.num,data2.sex);
    
    fclose(fp); // 关闭
    
    
    printf("n_write->:%d,n_read->:%d\n",n_write,n_read);    // 读写的次数是根据对应函数的第三个参数来的,读是写多少就是多少,写是根据实际次数
​
    return 0;
} 
fputc()原型
int fputc(int char, FILE *stream)
参数
char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。
返回值
如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    FILE *fp;
    
    char *str = "My name nianxing_su!\n";
    char *str1 = "I am a man!";
    int len = strlen(str);
    fp = fopen("./syh.txt","w+");
    for(int i = 0; i < len; i++){
        fputc(*str,fp);     // 写入一个字符
        str++;
    }
    fclose(fp);
    
    
    fp = fopen("./syh.txt","a+");
    fputs(str1,fp); // 写入字符串到文件
    fclose(fp);
    
    return 0;
} 

fputs()函数原型
int fputs(const char *str, FILE *stream)
参数
str -- 这是一个数组,包含了要写入的以空字符终止的字符序列。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。
返回值
该函数返回一个非负值,如果发生错误则返回 EOF。
feof()函数原型
int feof(FILE *stream)
参数
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
返回值
当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。
​
***需要配合循环使用,当到达结束标识符时返回不为0,否则返回0
结束时时一个数,其他是正数,结束之前是正数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
​
​
int main(int argc, char **argv) // atgc是参数个数    atgv是参数数组
{   
    FILE *fp;
    char c;
    fp = fopen("./syh.txt","r+");
    while(!feof(fp)){       // 读取到结束标识符时返回不为0,否则返回0
        c = fgetc(fp);  // 读取一个字符
        printf("%c",c);
    }
    fclose(fp);
    
    return 0;
} 
fgetc函数原型
int fgetc(FILE *stream)
参数
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。
返回值
该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
fgets函数原型
char *fgets(char *str, int n, FILE *stream)
参数
str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
返回值
如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。
如果发生错误,返回一个空指针。
​
***C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

  • 34
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值