Linux编程(一):标准I/O学习笔记

标准I/O

流的打开

fopen函数

下列函数可用于打开一个标准I/O流:

FILE *fopen(const char *path,const char *mode);

成功时返回流指针(大于0的值);出错时返回NULL

mode参数:

"r"或"rb"以只读方式打开文件,文件必须存在
"r+"或"r+b"以读写方式打开文件,文件必须存在
"w"或"wb"以只写方式打开文件,若文件存在则文件长度清为0。若文件不存在则创建啊
"w+"或"w+b"以读写方式打开文件,其他同"w"。可读指的是文件清空后新写入的内容可读
"a"或"ab"以只写方式打开文件,若文件不存在则创建;向文件写入的数据被追加到文件末尾。
"a+"或"a+b"以读写方式打开文件。其他同"a"。

当给定"b"参数时,表示以二进制方式打开文件,但Linux下忽略该参数。

打开一个标准I/O流的六种不同的方式

限制rwar+w+a+
文件必须已存在
擦除文件以前的内容
流可以读
流可以写
流只可在尾端处写

for example:

#include <stdio.h>
int main()
{
    FILE *fp;
    if((fp=open("test.txt","r+"))==NULL)
    {
        printf("fopen error\n");
        return -1;
    }
    else
    {
        printf("fopen success\n");
    }
    return 0;
}

fopen新建文件权限

  • fopen()创建的文件默认访问权限是0666(rw-rw-rw-),可实际最终的权限受``umask`影响
  • Linux系统中``umask设定会影响文件的访问权限,其规则为(0666&~umask),系统umask`默认为0222,通过规则计算得到的最终权限是644
  • 用户可以通过``umask`函数修改相关设定,修改只影响当前程序
  • 如果希望``umask不影响文件访问权限,该设定为0,即umask(0);`

处理错误信息

extern int errno;
void perror(const char *s);
char *strerror(int errno);
  • errno存放错误号
  • perror先输出字符串s,再输出错误号对应的错误信息
  • strerror根据错误号返回对应的错误信息

for example1:

#include <stdio.h>
int main()
{
    FILE *fp;
    if((fp=fopen("test.txt","r+"))==NULL)
    {
        perror("fopen");
        return -1;
    }
    else
    {
        printf("fopen success\n");
    }
    return 0;
}
//output:  fopen:No such file or directory

for example2:

#include <stdio.h>
#include <string.h>//strerror 头文件
#include <errno.h>//errno 头文件
int main()
{
    FILE *fp;
    if((fp=fopen("test.txt","r+"))==NULL)
    {
        printf("fopen:%s\n",strerror(errno));
        return -1;
    }
    else
    {
        printf("fopen success\n");
    }
    return 0;
}
//output:  fopen:No such file or directory

流的关闭

int fcloe(FILE *stream);

  • fclose()调用成功返回0,失败返回EOF,并设置errno
  • 流是有缓冲的,往流里面写入时,先写入流的缓冲区中,当缓冲区满了后才会写到实际的文件中
  • 流关闭时自动刷新缓冲中的数据并释放缓冲区
  • 当一个程序正常终止时,所有打开的流都会被关闭
  • 流一旦关闭后就不能执行任何操作

程序中能够打开的文件或流的个数有限制,如何测试?

思路:循环打开流,成功则计算器累加,直到出错为止

答案:1021+stdin+stdout+stderr=1024

#include <stdio.h>
#include <string.h>
int main()
{
    FILE *fp;
    int cout=0;
    while((fp=fopen("1.txt","w"))!=NULL)
    {
        cout++;
    }
    printf("cout:%d\n",cout);
    return 0;
}

流的读写

读写一个字符:fgetc()/fputc()一次读/写一个字符

读写一行:fgets()/fputs()一次读/写一行

读写若干个对象:fread()/fwrite()每次读/写若干个对象,而每个对象具有相同的长度

按字符输入
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
  • 成功时返回读取的字符;若到文件末尾或出错时返回EOF
  • getchar()等同于fgetc(stdin)

for example

#include <stdio.h>
int main()
{
    int c;
    c=fgetc(stdin);
    printf("%c\n",c);
    FILE *fp;
    int ch,count=0;
    if((fp=fopen("1.txt","r"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    while((ch=fgetc(fp))!=EOF)
    {
        count++;
    }
    printf("total %d bytes\n",count);
    fclose(fp);
    return 0;
    
}
按字符输出
#include <stdio.h>
int fputc(int c,FILE *stream);
int putc(int c,FILE *stream);
int putchar(int c);
  • 成功时返回写入的字符;出错时返回EOF
  • putchar(c)等同于fputc(c,stdout)

for example

#include <stdio.h>
int main()
{
    fputc('a',stdout);
    putchar('\n');
    FILE *fp;
    int ch;
    if((fp=fopen("1.txt","w"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    for(ch='a';ch<='z';ch++)
    {
        fputc(ch,fp);
    }
    fclose(fp);
    return 0;
    
}

exercise1:

如何利用fgetc/fputc实现文件的复制

#include <stdio.h>
int main()
{
    FILE *fps,*fpd;
    int ch;
    if((fps=fopen("1.txt","r"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    if((fpd=fopen("2.txt","w"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    while((ch=fgetc(fps))!=EOF)
    {
        fputc(ch,fpd);
    }
    fclose(fps);
    fclose(fpd);
    return 0;
}
按行输入
#include <stdio.h>
char *gets(char *s);
char *fgets(char *s,int size,FILE *stream);
  • 成功时返回s,到文件末尾或出错时返回NULL
  • gets不推荐使用,容易造成缓冲区溢出,未限定输入的长度
  • 遇到’\n’或已输入size-1个字符时返回自动添加结束符’\0’

for example

#include <stdio.h>
#define N 6
int main()
{
    char buf[N];
    fgets(buf,N,stdin);
    printf("%s",buf);
    return 0;
}
按行输出
#include <stdio.h>
int puts(const char *s);
int fputs(const char *s,FILE *stream);
  • 成功时返回输出的字符个数;出错时返回EOF
  • puts将缓冲区s中字符串输出到stdout,并追加’\n’
  • fputs将缓冲区s中的字符串输出到stream

for example

#include <stdio.h>
int main()
{
    puts("hello world");
    FILE *fp;
    char buf[]="hello world";
    if((fp=fopen("1.txt","a"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    fputs(buf,fp);
    fclose(fp);
    return 0;
    
}

exercise2:

如何统计一个文本文件包含多少行?

如何判断读取了一行?

#include <stdio.h>
#include <string.h>
int main()
{
    FILE *fp;
    int line=0;
    char buf[64];
    if((fp=fopen("data.txt","r"))==NULL)
    {
        perror("fopen");
        return -1;
    }
    while((fgets(buf,64,fp))!=NULL)
    {
        if(buf[strlen(buf)-1]=='\n')line++;
    }
    return 0;
}
按指定对象读写
#include <stdio.h>
size_t fread(void *ptr,size_t size,size_t n,FILE *fp);
size_t fwrite(const void *ptr,size_t size,size_t n,FILE *fp);
  • 成功返回读写的对象个数;出错时返回EOF

for example

#include <stdio.h>
#include <iostream>
using namespace std;
struct student{
    int no;
    char name[8];
    float score;
}s[]={{1,"hu",100},{2,"hui",98}};
int main()
{
    FILE *fp;
    if((fp=fopen("1.txt","w+"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    fwrite(s,sizeof(student),2,fp);
    struct student tmp;
    fread(&tmp,sizeof(student),2,fp);
    cout<<tmp.name<<" "<<tmp.no<<" "<<tmp.score<<endl;
    fclose(fp);
    return 0;
}
小结
  • fgetc/fputc操作文本文件或二进制数据文件读写,按字符读写,每次操作一个字符,效率低,
  • fgets/fputs按行读写,只能处理文本文件读写,二进制文件包含0,适合是字符串读写,对于0来说理解为字符串的终止符
  • fread()/fwrite()按照指定对象读写,文本文件和二进制文件都能处理,可以指定读写大小,效率高

exercise3:

如何利用fread/fwrite实现文件的复制

#include <stdio.h>
#define N 64
int main()
{
    FILE *fps,*fpd;
    char buf[N];
    int n;
    if((fps=fopen("1.txt","r"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    if((fpd=fopen("2.txt","w"))==NULL)
    {
        perror("fopen");
        return 0;
    }
    while((n=fread(buf,1,N,fps))>0)
    {
        printf("n=%d\n",n);
        for(int i=0;i<n;i++)
        {
            printf("buf[%d]=%c\n",i,buf[i]);
        }
        fwrite(buf,1,n,fpd);
    }
    fclose(fps);
    fclose(fpd);
    return 0;
}

流的刷新

流自动刷新缓冲区的几种情形

  • 流的缓冲区满了 ,流的缓冲区出现换行符时
  • 全缓冲只有缓冲区满了才会刷新,行缓冲区遇到换行符或缓冲区满了都会刷新
  • 流关闭时会把缓冲内的数据写到文件中
  • fflush刷新流缓冲
#include <stdio.h>
int fflush(FILE *fp);
  • 成功时返回0;出错时返回EOF
  • 将流缓冲区中的数据写入实际的文件
  • Linux下只能刷新输出缓冲区

for example

#include <stdio.h>
int main()
{
    FILE *fp;
    if((fp=fopen("1.txt",""))==NULL)
    {
        perror("fopen");
        return 0;
    }
    fputc('a',fp);//a字符写到流的缓冲区里,实际没有写到文件中
    fflush(fp);//刷新流的缓冲区 缓冲区的内容会写到实际的文件中
    while(1);
    return 0;
}

流的定位

#include <stdio.h>
long ftell(FILE *stream);
long fseek(FILE *stream,long offset,int whence);
void rewind(FILE *stream);
  • ftell()成功时返回流的当前读写位置,出错时返回EOF
  • fseek()定位一个流,成功时返回0.出错时返回EOF
  • whence参数:SEEK_SET/SEEK_CUR/SEEK_END
  • offset参数:偏移量,可正可负
  • rewind()将流定位到文件开始位置
  • 读写流时,当前读写位置自动后移

示例一(在文件末尾追加字符’t’)

FILE *fp=fopen("1.txt","r+");
fseek(fp,0,SEEK_END);
fputc('t',fp);

示例二(获取文件长度)

FILE *fp=fopen("1.txt","r+");
fseek(fp,0,SEEK_END);
printf("length is %d\n",ftell(fp));

判断流释放出错和结束

#include <stdio.h>
int ferror(FILE *stream);
int feof(FILE *stream);
  • ferror()返回1表示流出错;否则返回0
  • feof()返回1表示文件已到末尾;否则返回0

格式化输出

#include <stdio.h>
int printf(const char *fmt,...);
int fprintf(FILE *stream,const char *fmt,...);
int sprintf(char *s,const char *fmt,...);
  • 成功时返回输出的字符个数;出错时返回EOF

for example

以指定格式"年-月-日"分别写入文件和缓冲区

#include <stdio.h>
int main()
{
    int year,month,date;
    FILE *fp;
    char buf[64];
    year=2020;
    month=11;
    date=22;
    fp=fopen("1.txt","a+");
    fprintf(fp,"%d-%d-%d\n",year,month,date);
    sprintf(buf,"%d-%d-%d\n",year,month,date);
    printf("buf:%s",buf);
    return 0;
}

exercise

  • 每隔1秒向文件data.txt写入当前系统时间,格式如下:1, 2014-10-15 15:16:42
  • 该程序无限循环,直到按Ctrl+C中断程序
  • 每次执行程序时,系统时间追加到文件末尾,序号递增
  • time()用来获取系统时间(秒数)
  • localtime()将系统时间转换成本地时间
  • sleep()实现程序睡眠
  • 以何种方式打开流?
  • 流的缓冲类型对文件写入的影响
#include <stdio.h>
#include <unistd.h>//sleep
#include <time.h>// time localtime
#include <string.h>

int main()
{
    FILE *fp;
    int line=0;
    char buf[64];
    time_t t;
    struct tm *tp;
    if((fp=fopen("data.txt","a+"))==NULL)
    {
        perror("fopen");
        return -1;
    }
    while((fgets(buf,64,fp))!=NULL)
    {
        if(buf[strlen(buf)-1]=='\n')line++;
    }

    while (1)
    {
        time(&t);
        tp=localtime(&t);
        fprintf(fp,"%02d, %d-%02d-%02d %02d:%02d:%02d\n",++line,tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);
        fflush(fp);
        sleep(1);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

H_Mike

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

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

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

打赏作者

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

抵扣说明:

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

余额充值