IO进程(标准IO)

知识点链接

https://www.yuque.com/aihenaobaijin/camuoq/lscmvf6z1arklau4?singleDoc# 《IO进程》

函数接口

打开文件fopen

man 3 fopen

FILE *fopen(constchar*path,constchar*mode);

功能:打开文件

参数:

path:打开的文件路径

mode:打开的方式

r:只读,当文件不存在时报错,文件流定位到文件开头

r+:可读可写,当文件不存在时报错,文件流定位到文件开头

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

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

a:追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾

a+:读和追加,文件不存在创建,存在追加,读文件流定位到文件开头,写文件流定位到文件末尾

注:当a+的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置

返回值:

成功:文件流

失败:NULL,并且会设置错误码

补充:

perror ( )用来将上一个函数发生错误的原因输出到标准设备 (stderr) 。参数 s 所指的字符串会先打印出, 后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你设置的一些信息和现在的errno所对应的错误一起输出。

关闭文件fclose

int fclose(FILE* stream);
功能:关闭文件
参数:stream:文件流

文件读写操作

读一个字符:fgetc()

int fgetc(FILE * stream);

功能:从文件中读取一个字符,并将当前文件指针位置向后移动一个字符

参数:stream:文件流

返回值:成功:读到的字符

失败或读到文件末尾:EOF(-1)

写一个字符:fputc()

int fputc(int c, FILE * stream);

功能:向文件中写入一个字符, 成功写入后文件指针会自动向后移动一个字节位置

参数:c:要写的字符

stream:文件流

返回值:成功:写的字符的ASCII

失败:EOF(-1)

读一个字符串:fgets()

char *fgets(char *s,int size, FILE *stream);

功能:从文件中每次读取一行字符串

参数: s:存放字符串的地址

size:期望一次读取的字符个数

stream:文件流

返回值:成功:s的地址

失败或读到文件末尾:NULL

特性: 每次实际读取的字符个数为size-1个,会在末尾自动添加\0

每次读一行,遇到\n或者到达文件末尾后不再继续读下一行

并把它存储在s所指向的字符串内

写一个字符串:fputs()

int fputs(const char *s, FILE *stream);

功能:向文件中写字符串

参数:s:要写的内容

stream:文件流

返回值:成功:非负整数

失败:EOF

feof和ferror

int feof(FILE * stream);

功能:判断文件有没有到结尾,也就是当前所在位置后面还有没有字符

返回:如果到达文件末尾,返回非零值。如果后面还有字符则返回0

int ferror(FILE * stream);

功能:检测文件有没有出错

返回:文件出错,返回非零值。如果没有出错,返回0。

二进制读写 fread()和fwrite()

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

功能:从文件流读取多个元素(将二进制数据从文件读出)

参数: ptr :是一个指针,是存放数据的存储空间的起始地址,用来存放读取元素

size :元素大小 sizeof(元素数据类型)

nmemb :读取元素的个数

stream :要读取的文件流

返回值:成功:读取的元素的个数

读到文件尾或失败: 0

size_t fwrite(const void*ptr, size_t size, size_t nmemb,FILE *stream);

功能:将二进制数据写入文件

参数: ptr :是一个指针,保存要输出数据的空间的地址

size :要写入的字节数 sizeof(数据类型)

nmemb : 要进行写入元素的个数

strem: 目标文件流指针

返回值:成功:写的元素个数

失败 :-1

重定向流到文件freopen

FILE *freopen(const char *pathname,const char *mode, FILE* fp);

功能:将指定的文件流重定向到打开的文件中

参数:path:文件路径

mode:打开文件的方式(同fopen)

fp:文件流指针

返回值:成功:返回打开的文件流指针

失败:NULL

 文件定位操作

void rewind(FILE *stream);

功能:将文件位置指针定位到起始位置

参数:stream:文件流

int fseek(FILE *stream,long offset,int whence);

功能:文件的定位操作

参数:stream:文件流

offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移

whence:相对位置:

SEEK_SET:相对于文件开头

SEEK_CUR:相对于文件当前位置

SEEK_END:相对于文件末尾

返回值:成功:0

失败:-1

注:当打开文件的方式为a或a+时,fseek不起作用

补充:其中SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2

fseek(fp,100,0);把fp指针移动到离文件开头100字节处.

fseek(fp,100,1);把fp指针移动到离文件当前位置100字节处

ffseek(fp,-100,2);把fp指针退回到离文件结尾100字节处

long ftell(FILE *stream);

功能:获取当前的文件位置

参数:要检测的文件流

返回值:成功:当前的文件位置

失败:-1

 编程练习

 练习1:通过fgetc和fputc实现"cat 文件名"功能(将文件内容在终端显示)

#include <stdio.h>
/* cat 文件名:查看文件内容,显示到终端。
   步骤:
        1.打开文件 fopen
        2.循环用fgetc获取文件内容
        3.当读到文件末尾标志EOF时结束
        4.将读取文件内容用fputc打印到终端
        5.关闭文件
*/
int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("err:%s<filename>\n", argv[0]);//提示正确格式
        return -1;
    }
    //1.打开文件
    FILE *fp = fopen(argv[1],"r");
    if (NULL == fp)
    {
        printf("failed\n");
    }
    else
    {
        printf("seccess\n");
    }
    //2.循环用fgetc读文件,只要读到就fputc打印到终端
    char ch;
    while ((ch = fgetc(fp) )!= EOF)
    {
        fputc(ch, stdout);//将读到字符打印到终端
    }
    //3.关闭文件
    fclose(fp);
    return 0;
}

 练习2:通过fgets实现"wc -l 文件名"命令功能(计算文件行数)

#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("err:%s <filename>\n", argv[0]);
        return -1;
    }

    FILE *fp = fopen(argv[1], "r");
    if (NULL == fp)
        printf("fopen failed\n");
    else
        printf("fopen seccess\n");
    
    char str[100];
    int len = 0;
     //循环fgets读文件, 只要读到就判断是否有\n, 如果有就累加行数
    while (fgets(str, 100, fp))
    {
        fputs(str, stdout);
        if (str[strlen(str) - 1] == '\n')
            len++;
    }
    printf("len=%d\n", len);//wc -l会少一行,因为最后一行没有换行
    fclose(fp);
    return 0;
}

练习3: 实现“head -n 文件名”命令的功能

atoi功能: "123" -> 123(整型)

#include <stdio.h>
#include <stdlib.h>
#define N 32
int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("usage:%s <line><filename>\n", argv[0]);
        return -1;
    }

    FILE *fp = fopen(argv[2], "r");
    if (NULL == fp)
    {
        perror("open error");
        return -1;
    }
    char buf[N];
    int line = atoi(argv[1] + 1);
    while (fgets(buf, N, fp) != NULL &&  line)
    {
        fputs(buf, stdout);
            line--;
    }
    fclose(fp);
    return 0;
}

题目要求:编程读写一个文件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

整体思路:

1. 打开文件fopen,循环往文件写内容

2. 每隔1s写入一行,sleep(1);

3. 计算文件行数,wc -l

4. 计算当前时间,转换成年月日、时分秒,time,localtime

man 2 time

time_t time(time_t *t);

如果t是空指针,直接返回当前时间。如果t不是空指针,返回当前时间的同时,将返回值赋予t指向的内存空间。

man 3 localtime

struct tm *localtime(const time_t *timep);

返回值是结构体指针,所指结构体封装着年月日时分秒

5. 字符串拼接函数:strcpy/strcat(dest, src)、sprintf、fprintf

fprintf:

格式化输出到流(stream)文件中,返回值是输出的字符数,发生错误时返回一个负值

int fprintf( FILE *stream, const char *format, ... );

sprintf:

格式化输出发送到buffer(缓冲区)中,返回值是写入的字符数量

int sprintf( char *buffer, const char *format, ... );

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
    FILE *fp = fopen("time.txt", "a+");
    if (NULL == fp)
        printf("fopen failed\n");
    else
        printf("fopen success\n");

    char str[100];
    int len = 0;
    while (fgets(str, 100, fp) != NULL)
    {
        if (str[strlen(str) - 1] == '\n')
            len++;
    }
    time_t tm;     // 获取系统当前时间,并保存在变量t中,存的是秒数
    struct tm *ge; // struct tm*localtime(const time_t *timep)//参数:保存当前秒数的地址
    // 返回值:tm结构体指针,转换的本地时间保存在指针指向的结构体中
    while (1)
    {
        time(&tm);
        ge = localtime(&tm);
        // 输入到指定文件中
        fprintf(fp, "%d:%d-%d-%d %d:%d:%d\n", ++len, ge->tm_year + 1900, ge->tm_mon + 1, ge->tm_mday, ge->tm_hour, ge->tm_min, ge->tm_sec);
        fflush(fp);
        sleep(1);
        // 把当前时间给到一个字符串
        sprintf(str, "%d:%d-%d-%d %d:%d:%d\n", len, ge->tm_year + 1900, ge->tm_mon + 1, ge->tm_mday, ge->tm_hour, ge->tm_min, ge->tm_sec);
        // 终端打印字符串内容
        fputs(str, stdout);
        }
    fclose(fp);
    return 0;
}
  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值