LinuxC——1.文件读写

LinuxC——1.文件读写

1.??文件IO

从CPU到文件是Output的一个过程,从文件到CPU是一个Input的过程,这个过程是以CPU为点的

2.??系统函数

  • open:打开文件
  • close:关闭文件
  • read:读数据
  • write:写数据
  • lseek:移动文件中读写位置
  • dup:文件书写位置重定位函数,重定位可以写入另一个文件
  • fcntl:文件描述符设置
  • ioctl:一个特殊函数

3.??文件读写的简单例子

  • open函数:通过fd,找到块设备文件

    • 文件系统是一个程序代码,组织块设备所有文件
    • 文件系统属于OS一部分
    • 找到文件后,调用块设备驱动,打开文件
      • 打开成功,返回非负操作符
      • 打开失败,返回-1
  • write函数:利用打开成功返回的,向文件里面写数据
  • lseek函数:利用文件描述符,将文件读写位置调整到文件相应位置
    • why设置文件头
    • write的时候,文件读写位置已经到了末尾
  • read函数:从文件头开始,读取指定长度的数据到buf中
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
        int fd = 0;

        fd = open("./file.txt", O_RDWR);
        if(-1 == fd) {
                printf("open fail\n");
                return 1;
        }else {
                printf("open ok\n");
        }

        char buf[] = "Steve Yu, today is nice";
        write(fd, (void *)buf, strlen(buf));

        lseek(fd, SEEK_SET, 0);

        char buf2[30] = {0};
        read(fd, buf2, sizeof(buf));

        puts(buf2);

  			close(fd);
        return 0;
}

4.??文件打开后,OS做了什么?

  1. 记录打开文件信息

    1. 程序运行后是一个进程,OS会创建一个task_struct的结构体,记录运行的各种信息
    2. open将文件打开后,在task_struct会创建一些数据结构,用来创建当前进程的打开文件的信息,后面所有的都依赖这些信息
  2. open函数会申请一段内存空间(内核缓存)
    1. 内核缓存是在OS的一个空间,比如char buf[100],就开辟了缓存
    2. 由os开辟的叫内核缓存
  3. open为啥要开辟内存缓存空间?

    内存读写 > 磁盘读写,我们会省时间

  4. open仅仅开辟了内存缓存空间,并没有数据,只有读写数据的时候

    先将数据读到内核缓存中,之后下层会让内存缓存和磁盘数据进行交换

  5. 读写的时候,数据的流动?

    硬件 -> 驱动缓存 -> 内核缓存 -> 应用程序中的数组

(仅掌握open函数,其余函数已经过时)

5.??指定宏

  1. O_RDONLY:只读
  2. O_WRONLY:只写
  3. O_RDWR:可读可写

以上三个不可以用 | 进行宏运算,而可以与以下进行宏运算

  1. O_TRUNC:打开进行清空
  2. O_APEND:打开后写数据追加
  3. O_NONBLOCK和O_AYNC:非阻塞,同步

flag参数之O_CREAT、O_EXCL

  1. O_CREAT:新建一个文件
  2. O_EXCL:O_EXCL和O_CREAT同时被指定,打开文件,如果文件存在,就报错

可以使用O_RDWR|O_CREAT进行组合,那么可以不存在进行创建,存在不打开的功能

6.??文件描述符

  1. 文件描述符是什么?

文件描述符指向打开的文件,后面read/write/close等操作,都是基于文件描述符进行操作

  1. 文件描述符池

每个程序运行起来后,就是一个进程,系统给每个进程分配01023的描述符的范围,返回的文件描述符,是在01023的某个数字

  1. 为啥第一个打开的文件,open返回的是3?

open返回的文件描述符是规则的:

  • open返回文件描述符池中,返回当前没用的最小的一个
  • 进程运行起来,0/1/2会默认使用,最小没用的是3
  1. fopen文件指针

fopen是C库标准io函数

fopen成功后,FILE*的文件指针,打开了文件

fopen成功后,返回的是FILE*文件指针,指向打开的文件

  1. 对于Linux C库,fopen对open进行二次封装

7.??errno和perror

Linux中,如果像上述中,打开失败,那么就直接失败,遇到比较难排查的错误原因,难以查处具体错误

  1. 什么是errno?

errno我们查看man 3 errno中,可以看到,一系列错误宏定义,我们include "errno.h"即可

printf("%d: open error", errno);

这样即可发现17:open error,打开错误

2.具体错误

我们仅仅知道错误号,不知道具体错误,怎么办呢?

  • perror函数:我们通过man 3 perror,可以查看到错误号的具体使用

    perror可以打印的错误号以及具体错误

perror("open fail");

我们可以知道,控制台打印:open fail: File exists

3.使用man 2 open进行查看ERRORS下错误号

比如EACCES,不允许访问

我们因为记不住错误号,也记不住宏定义,所以,我们有了perror

8.??close、write、read

  1. close函数

close(fd):不主动关闭,应用也会自动关闭fd,但是我们得进行手动关闭

  1. close函数做了啥
  • open打开的时候会在task struct中创建结构体空间,如果文件关闭,那么该结构体空间被释放

    类似free(空间地址)

  • malloc和free是给C调用的库看书,Linux在释放的时候,有自己的释放函数

好习惯必须关闭,否则我们在生产环境,容易内存溢出

9.??task struct结构体

  1. 结构体在存在在运行的进程中,在task struct是程序在运行的时候进行开辟
  2. 进程运行结束,linux系统会调用自己的系统函数,进行释放task struct

10.??文件描述符

有关0/1/2文件描述符

  • stdin,文件描述符为0,0代表键盘,实现键盘输入

键盘->键盘驱动缓存->内核缓存->应用缓存

#include <unistd.h>
#include <stdio.h>
int main() {
        int ret = 0;
        char buf[30] = {0};
        ret = read(0, (void *)buf, 30);
        if(-1 == ret) {
                perror("read fail");
                return -1;
        }
        puts(buf);
        return 0;
}

scanf底层调用read(0, buf, size)这个,这样就能兼容不同操作系统

  • close(0),scanf还能工作不?

答案是不可以,用perror打印,会得到bad description的

  • stdout,文件描述符为1,使用1,则可以进行显示器显示
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
        int fd = 1, ret = 0;

        char buf[] = "steve\n";
        write(fd, buf, sizeof(buf));

        close(fd);
        return 0;
}

假设我们write(1, &a, sizeof(a)), a是一个int值,那么会打印一个(char)a进行

  • close(1)

printf不能工作

  • stderr, 文件描述符是2,是标准出错输出

使用2文件描述符也能进行打印

1打印普通信息,2打印报错信息

  • close(2)

perror是通过2进行打印,如果close(2),则不能进行perror

  • 宏定义

0:STDIN_FILENO

1:STDOUT_FILENO

2:STDERR_FILENO

11.??lseek

lseek用来调整读写的位置,调用成功返回偏移量,调用失败返回-1

我们可以通过lseek获取文件大小

1.fd:打开文件

2.whence:粗定位

SEEK_SET:起始位置

SEEK_CUR:当前读写位置

SEEK_END:文件末尾位置

3.offset:微调

进行偏移,正数向前移动,负数向后

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

int main() {
        int fd = 0, ret = 0;

        fd = open("./file.txt", O_RDONLY);

        if(-1 == fd) {
                perror("file open failed");
                exit(-1);
        }

        ret = lseek(fd, 0, SEEK_END);

        printf("文件大小%d\n", ret);
        return 0;
}

4.使用od -c filename,可以查看以字符进行显示字符

12.??进程表和文件描述表

进程表:task_struct

  • 这个结构体成员多达300个
  • 每个进程运行起来后,linux系统会开辟task_struct 结构体
  • task_struct专门用于进程运行中,涉及进程相关信息

13.??共享操作文件

  • 同一个进程共享相同文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
void print_error(char* str) {
        perror(str);
        exit(-1);
}
int main() {
        int fd1, fd2;

        fd1 = open("./file.txt", O_RDWR);

        if(-1 == fd1) print_error("open fail");

        fd2 = open("./file.txt", O_RDWR);

        if(-1 == fd2) print_error("open fail");

  			// 写入操作
        return 0;
}

存在相互覆盖的关系

解决方案:使用O_APPEND进行追加

  • 多个进程共享相同文件
gcc share_op_file.c -o a
gcc share_op_file.c -o b
./a
./b

那么会出现覆盖情况

解决方案:也使用O_APPEND进行追加

14.??dup和dup2

  1. int dup(int fd)
  • 在unistd.h中
  • dup用来复制文件描述符,得到一个新的文件描述符,指向原来的文件,指向最小没用的那一个
fd2 = dup(fd1)
  1. int dup2(int oldfd, int newfd)
  • 在unistd.h中
  • dup2指定一个文件描述符,用来复制文件描述符,得到一个新的文件描述符,如果已经打开,则关闭后再次打开
fd2 = (fd1, 4)
  1. dup、dup2的意义

实现文件共享操作,不使用APPEND也不会出现文件覆盖。使用dup或dup2的时候,永远只有一个文件表。

15.??实现文件重定位

步骤:

  1. 打开文件fd
  2. close(1)
  3. 进行复制fd到1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
        int fd1;
        fd1 = open("data.txt", O_RDWR|O_CREAT);
        close(1);
        dup(fd1);
        printf("Hello World");
        return 0;
}

当我们文件描述符写死了,那么可以进行文件重定位来进行,linux底层的重定位>是使用dup/dup2作为底层的支持

16.fcntl函数

int fcntl(int fd, int cmd, ... /* arg */ );

fcntl是文件控制函数(file control)

  • fd:指向打开文件
  • cmd:控制命令
    • F_DUPFD

      • 模拟DUP
    • F_GETFL、F_SETFL
      • 获取设置文件状态标注,比如open没有指定O_APPEND,可以使用fcntl进行补设
    • F_GETFD、F_SETFD(文件描述符)
    • F_GETOWN、F_SETOWN(OWN)
    • F_GETLK、F_SETLK、F_SETLKW(加锁)

    先掌握前两个F_DUPFDF_GETFL、F_SETFL

模拟DUP:

fcntl(fd, F_DUPFD, 0);// 第三个参数没有,用0表示

模拟DUP2:

fcntl(fd, F_DUPFD, 1);// 模拟DUP2,进行用1

设置

fcntl(fd, F_SETFL, O_RDWR|O_APPEND); // 修改打开时的Flag,返回新设置的标志

保留原标志,加新标志

flag = fcntl(fd, F_GETFL); // 获取
fcntl(fd, F_SETFL, flag|O_APPEND); // 叠加

原文地址:https://www.cnblogs.com/littlepage/p/12637233.html

时间: 2024-10-09 09:33:07

LinuxC——1.文件读写的相关文章

Node.JS 文件读写,把Sheet图集转换为龙骨动画图集

Node.JS 文件读写,把Sheet图集数据转换为龙骨动画图集数据 var fs = require("fs") var readline = require("readline"); var rl = readline.createInterface({ input:process.stdin, output:process.stdout }); var path = undefined; var dbName = undefined; rl.question(

Android中的文件读写全面总结

转载请注明出处:http://blog.csdn.net/bettarwang/article/details/41625187 在深入分析Java中的I/O类的特征及适用场合 一文中,我详细介绍了Java中的I/O,但是,如果以为Android中的I/O与Java中一样,那就大错特错了.实际上,它们有一定的相同之外,但更多的是区别,因为Android系统中的文件存放位置不同,读取方式也不一样.下面将详细介绍Android中的文件读写: 一.资源文件的读取,不需要在Manifest文件中添加权限

文件操作ofstream,open,close,ifstream,fin,按照行来读取数据, fstream,iosin iosout,fio.seekg(),文件写入和文件读写,文件拷贝和文件

 1.ofstream,open,close 写入文件 #include<iostream> #include<fstream> using namespace std; //通过ofstream的方式实现写入文件 open,close void main() { ofstream fout;  //ofstream输出文件 fout.open("E:\\1.txt");//打开文件 fout << "1234abcdef";

C语言文件读写操作总结

C语言文件操作 一.标准文件的读写 1.文件的打开 fopen() 文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了.当使用打开函数时,必须给出文件名.文件操作方式(读.写或读写),如果该文件名不存在,就意味着建立(只对写文件而言,对读文件则出错),并将文件指针指向文件开头.若已有一个同名文件存在,则删除该文件,若无同名文件,则建立该文件,并将文件指针指向文件开头. fopen(char

快速入门Python中文件读写IO是如何来操作外部数据的?

读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的. 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件). 读文件 要以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符 >>> f =

Python IO编程——文件读写

1.1   文件读写 1.1.1   读文件 >>> f = open('/root/python/hello.py','r')    #标识符r表示读 >>> f =open('/root/python/hello1.py', 'r')   #文件不存在报错 Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundE

RandomAccessFile 文件读写中文乱码解决方案!

RandomAccessFile 读写文件时,不管文件中保存的数据编码格式是什么   使用 RandomAccessFile对象方法的 readLine() 都会将编码格式转换成 ISO-8859-1 所以 输出显示是还要在进行一次转码 例子: package fileReadAndWrite; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; /*

转载-Python学习笔记之文件读写

Python 文件读写 Python内置了读写文件的函数,用法和C是兼容的.本节介绍内容大致有:文件的打开/关闭.文件对象.文件的读写等. 本章节仅示例介绍 TXT 类型文档的读写,也就是最基础的文件读写,也需要注意编码问题:其他文件的读写及编码相关详见专题的博文. open()   close()     with open(...) as ... 看以下示例就能了解 Python 的 open() 及 close() 函数.这边调用 read()方法可以一次读取文件的全部内容,Python把

iOS-Senior1-数据处理(文件读写)

1.Model的数据层的理解       1.1沙盒基础 沙盒定义:每个iOS应用程序都会为自己创建一个文件系统目录(文件夹),这个独立,封闭,安全的空间,叫做沙盒. 沙盒特点: 沙盒的文件夹及各个文件夹的作用   查找沙盒的两个方式: 1.点击finder -> 前往(左上角)- > 按住alt键  -> 资源库 -> Developer -> CoreSimulator -> (目标文件夹) 2.搜索 -> 终端 -> 命令行: 显示:defaults