IO进程—文件IO

本文详细介绍了Linux系统中的文件IO操作,包括概念、特点、标准IO与文件IO权限的区别,以及一系列关键函数的使用,如open、close、read、write和lseek等。同时,文章还涵盖了目录操作的相关函数,如opendir、readdir和closedir,并提供了多个示例代码来演示这些操作的实践应用。
摘要由CSDN通过智能技术生成

目录

概念

特点

标准IO和文件IO权限的区别

函数

打开文件

open

关闭文件

close

读函数

read

写函数

write

定位操作

lseek

标准IO和文件IO的对比

目录操作

函数

获取目录流:opendir

读目录:readdir

关闭目录:closedir


概念

系统中定义的一组用于输入输出的函数。

特点

  1. 没有缓冲机制,每次调用都会引起系统调用
  2. 围绕文件描述符进行操作,文件描述符是非负整数(>=0),并且是一次分配
  3. 文件IO默认打开三个文件描述符,分别是0(标准输入),1(标准输出),2(标准错误)
  4. 可以操作任意类型文件,d除外

标准IO和文件IO权限的区别

标准IO文件IO
r只读,文件不存在则报错:O_RDONLY
r+可读可写,文件不存在则报错:O_RDWR
w

只写,文件不存在则创建,存在则清空:

O_WRONLY | O_CREAT | O_TRUNC,0666

w+

可读可写,文件不存在则创建,存在则清空:

O_RDWR | O_CREAT | O_TRUNC,0666

a

追加,只写,文件存在则追加,不存在则创建:

O_APPEND | O_CREAT | O_WRONLY,0666

a+

追加,可读可写,文件存在则追加,文件不存在则创建:

O_APPEND | O_CREAT | O_RDWR,0666

函数

打开文件

open

格式:int open(const char *pathname, int flags);
功能:打开文件
参数:
    pathname:文件路径名
    flags:打开文件的方式
            O_RDONLY:只读
            O_WRONLY:只写
            O_RDWR:可读可写
            O_CREAT:创建
            O_TRUNC:清空
            O_APPEND:追加   
返回值:
    成功:文件描述符
    失败:-1
当第二个参数中有O_CREAT选项时,需要给open函数传递第三个参数,指定创建文件的权限 
int open(const char *pathname, int flags, mode_t mode);
创建出来的文件权限为指定权限值&(~umask)  //umask为文件权限掩码
/*
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
O_APPEND:追加
O_CREAT:创建
O_TRUNC:清空
 */
/*
r:
r+:
w:O_WRONLY|O_CREAT|O_TRUNC,0666;
w+:
a:
a+:
 */

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

int main(int argc, char const *argv[])
{
    int fd1 = open("./a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd1 < 0)
    {
        perror("open err");
        return -1;
    }
    printf("fd:%d\n", fd1);
    close(fd);
    return 0;
}

注意:

不同的进程打开相同的文件,文件指针各不相同

关闭文件

close

格式:int close(int fd);
功能:关闭文件
参数:fd:文件描述符

读函数

read

ssize_t read(int fd, void *buf, size_t count);
功能:从一个已打开的可读文件中读取数据
参数:
    fd:文件描述符
    buf:存放位置
    count:期望的个数
返回值:
    成功:实际读到的个数
    失败:返回-1,并设置errno号
    读到文件结尾:返回0
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    int fd = open("./a.txt", O_RDWR);
    if (fd < 0)
    {
        perror("open err");
        return -1;
    }
    printf("fd:%d\n", fd);
    //读写操作
    char buf[32] = {0};
    ssize_t s = read(fd, buf, 32);
    printf("%d %s\n", s, buf);

    write(fd,"nihao",strlen("nihao"));

    close(fd);
    return 0;
}

写函数

write

格式:ssize_t write(int fd, const void *buf, size_t count);
功能:向指定文件描述符中,写入 count个字节的数据。
参数:
    fd:文件描述符
    buf:要写的内容
    count:期望值
返回值:
    成功:实际写入数据的个数
    失败:-1

练习1:

用文件IO实现cp功能

命令行参数为:./a.out src dest

/*打开文件 循环读源文件写目标文件,
读到文件末尾循环结束,关闭文件 */

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

int main(int argc, char const *argv[])
{
    ssize_t s = 0;
    char buf[32] = {0};
    //打开文件
    int src = open(argv[1], O_RDONLY);
    if (src < 0)
    {
        perror("open src err");
        return -1;
    }
    int dest = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (dest < 0)
    {
        perror("open dest err");
        return -1;
    }
    printf("src:%d dest:%d\n", src, dest);

    //循环读源文件写目标文件,读到文件末尾循环结束
    while ((s = read(src, buf, 32)) != 0)
        write(dest, buf, s);

    //关闭文件
    close(src);
    close(dest);

    return 0;
}

定位操作

lseek

格式:off_t lseek(int fd, off_t offset, int whence);
功能:设定文件的偏移位置	
参数:
    fd:文件描述符
	offset:偏移量  				
		正数:向文件结尾位置移动
		负数:向文件开始位置
	whence:相对位置
		SEEK_SET   开始位置
		SEEK_CUR   当前位置
		SEEK_END   结尾位置
返回值:
    成功:文件的当前位置
	失败:-1
/*向文件中第 10 位置处写一个字符,在文件此时的位置
后 20个位置处,写一行字符串hello进去,
求此时文件的长度。 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
    int fd = open("./a.txt", O_RDWR);
    if (fd < 0)
    {
        perror("open err");
        return -1;
    }
    printf("fd:%d\n", fd);

    lseek(fd, 9, SEEK_SET);
    write(fd, "a", 1);

    lseek(fd, 20, SEEK_CUR);
    write(fd, "hello", 5);

    off_t off = lseek(fd, 0, SEEK_END);
    printf("len:%ld\n", off);
    return 0;
}

练习2:

向文件第10个位置处写一个字符,在文件此时的位置后20个位置处写一行“hello”进去,并求此时文件的长度。

/*向文件中第 10 位置处写一个字符,在文件此时的位置
后 20个位置处,写一行字符串hello进去,
求此时文件的长度。 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char const *argv[])
{
    int fd = open("./a.txt", O_RDWR);
    if (fd < 0)
    {
        perror("open err");
        return -1;
    }
    printf("fd:%d\n", fd);

    lseek(fd, 9, SEEK_SET);
    write(fd, "a", 1);

    lseek(fd, 20, SEEK_CUR);
    write(fd, "hello", 5);

    off_t off = lseek(fd, 0, SEEK_END);
    printf("len:%ld\n", off);
    return 0;
}

标准IO和文件IO的对比

标准IO文件IO
概念C库中定义的一组用于输入输出的函数在系统中定义的一组用于输入输出的函数
特点

1.有缓冲机制:数据会写到内存缓冲区,伪写入,需要刷新,效率高

2.围绕流来进行操作,FILE *

3.默认打开三个流:stdin、stdout、stderr

4.只能操作普通文件

5.可移植性更强一些

1.无缓冲机制:数据会及时冲刷到设备,但是效率低

2.围绕文件描述符操作,非负整数

3.默认打开三个文件描述符:0、1、2

4.可以操作任意类型的文件,除d以外,可操作设备文件

5.在软件设计层面具有可移植性,在Linux中的操作,不能用到Windows系统

函数

1.打开文件:fopen、freopen

2.关闭文件:fclose

3.读写操作:fgetc/fputc、fgets/fputs、fread/fwrite

4.定位操作:fseek、rewind、ftell

5.刷新函数:fflush

1.打开文件:open

2.关闭文件:close

3.读写操作:read/write

4.定位操作:lseek

目录操作

函数

获取目录流:opendir

格式:DIR *opendir(const char *name);
功能:获得目录流
参数:要打开的目录
返回值:
    成功:目录流
    失败:NULL

读目录:readdir

格式:struct dirent *readdir(DIR *dirp);
功能:读目录
参数:要读的目录流
返回值:
    成功:读到的信息    
    失败:NULL,设置errno号

返回值为结构体,该结构体成员为描述该目录下的文件信息
struct dirent {
        ino_t   d_ino;               /* 索引节点号*/
        off_t   d_off;               /*在目录文件中的偏移*/
        unsigned short d_reclen;     /* 文件名长度*/
        unsigned char  d_type;       /* 文件类型 */
        char    d_name[256];         /* 文件名 */
};

关闭目录:closedir

格式:int closedir(DIR *dirp);
功能:关闭目录
参数:dirp:目录流
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, char const *argv[])
{
    struct dirent *d;
    //打开目录
    DIR *dir;
    dir = opendir(".");
    if (dir == NULL)
    {
        perror("opendir err");
        return -1;
    }
    printf("opendir ok\n");

    d = readdir(dir);
    printf("%s\n",d->d_name);

    //关闭目录流d
    closedir(dir);
    return 0;
}


练习1:

实现ls功能

//实现ls
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, char const *argv[])
{
    struct dirent *d;
    //打开目录
    DIR *dir = opendir(".");
    if (dir == NULL)
    {
        perror("opendir err");
        return -1;
    }
    //读目录
    while ((d = readdir(dir)) != NULL)
    {
        if (d->d_name[0] != '.')
            printf("%s ", d->d_name);
    }
    putchar(10);

    //关闭目录
    closedir(dir);
    
    return 0;
}

练习2:

实现“head -n 文件名”命令的功能,用atoi函数将字符串转换成整型数

head -n 文件名:显示文件内容

//head -n 文件名
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    char buf[32] = {0};
    if (argc != 3)
    {
        printf("please input %s <-n> <filename>", argv[0]);
        return -1;
    }
    //处理argv[1],获取要显示到第几行
    int num = atoi(argv[1] + 1);
    //处理argv[2]
    //打开文件
    FILE *fp = fopen(argv[2], "r");
    if (fp == NULL)
    {
        perror("fopen err");
        return -1;
    }
    //打印前n行
    while (fgets(buf, 32, fp) != NULL)
    {
        if (buf[strlen(buf) - 1] == '\n')
            num--;
        printf("%s", buf);
        if (num == 0)
            break;
    }

    fclose(fp);
    return 0;
}

练习3:

编程读写一个文件test.txt,每隔1秒向文件中写入一行数据,类似这样: 

1,  2007-7-30 15:16:42  

2,  2007-7-30 15:16:43

该程序应该无限循环,直到按Ctrl+C中断程序。

再次启动程序写文件时可以追加到原文件之后,并且序号能够接续上次的序 号,比如: 

1,  2007-7-30 15:16:42

2,  2007-7-30 15:16:43

3,  2007-7-30 15:19:02

4,  2007-7-30 15:19:03

5,  2007-7-30 15:19:04

使用到time localtime fprintf sprintf 函数

思路:

  1. 打开文件,fopen,以a+的形式
  2. sleep(1)// 延时函数,使进程延时运行,参数是延时的时间
  3. 计算文件行数
  4. 计算时间:time,转换成年月日时分秒的形式:localtime
  5. 写到文件里:fprintf
/*
1.打开文件,fopen,a+
2.sleep(1)
3.计算文件行数
4.计算时间,time,转换成年月日,时分秒localtime
5.写到文件,fprintf 
 */
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    time_t t;
    struct tm *tm;
    int len = 0;
    char buf[32] = {0};
    //1.打开文件,fopen,a+
    FILE *fp = fopen("a.txt", "a+");
    if (fp == NULL)
    {
        perror("fopen err");
        return -1;
    }
    //计算文件行数
    while (fgets(buf, 32, fp) != NULL)
    {
        if (buf[strlen(buf) - 1] == '\n')
            len++;
    }
    //计算时间,time,转换成年月日,时分秒localtime
    while (1)
    {
        time(&t);
        tm = localtime(&t);
        //写到文件,fprintf
        fprintf(fp, "%d,%d-%d-%d %d:%d:%d\n", ++len,
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                tm->tm_hour, tm->tm_min, tm->tm_sec);
        fflush(NULL);
        sleep(1);
    }
    fclose(fp);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值