【1】标准IO

【1】标准IO(input\output)

1.概念:

标准IO是指在C库中提供的一组专门用于输入输出的函数

2.特点:

不仅在UNIX系统,在很多操作系统上都实现了标准I/O库
标准I/O库由ANSI C标准说明
标准I/O通过缓冲机制减少系统调用,实现更高效率
标准I/O在系统调用函数基础上构造的,它便于用户使用
标准IO默认打开了三个流:stdin、stdout、stderr

3.流:

定义:所有的I/O操作仅是简单的从程序移进或者移出,
这种字节流,就称为流

4.FILE:(文件流指针)

每个被使用的文件都在内存中开辟一个区域,用来存放文件
的有关信息,这些信息是保存在一个结构体类型的变量中,
该结构体类型是由系统定义的,取名为FILE。
标准I/O库的所有操作都是围绕流(stream)来进行的,
在标准I/O中,流用FILE *来描述。
使用vi -t FILE
vi -t FILE —> ctrl+](追朔源码定义)–>struct _IO_FILE
ctrl+t:回退上一次定义

【2】缓存区:

1.全缓存:与文件相关

​ 刷新缓存区的条件:
​ 1)程序正常退出
​ 2)缓存区满刷新
​ 3)fflush强制刷新
​ fflush( FILE* 流指针);

2.行缓存:与终端相关

​ 刷新缓存区的条件:
​ 1)\n刷新
​ 2)程序正常退出
​ 3)缓存区满刷新
​ 4)fflush强制刷新

3.不缓存:没有缓存区,stderr

练习:测试标准输出缓存区的大小
/**

** Created by 24122 on 2022/4/28.

**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{  
int i;
    for (i = 0; i < 256; i++){
        if (i < 10)
        {
            printf("000%d", i);
        }
        else if (i >= 10 && i < 100)
        {
            printf("00%d", i);
        }
        else if (i >= 100)
        {
            printf("0%d", i);
        }
    }
    while (1);
    /*标准输入(stdin) 标准输出(stdout) 标准出错(stderr)
    int len;
    printf("hello world!\n");
    len = stdout->_IO_buf_end-stdout->_IO_buf_base;
    printf("len:%d\n", len);
     */
    return 0;
}

【3】打开文件:

1.FILE *fopen

​ FILE *fopen(const char *path, const char *mode);
​ 功能:打开文件
​ 参数:path:文件路径
​ mode:打开文件的方式
​ r:只读,文件不存在,会报错
​ r+:可读可写,文件不存在,会报错
​ w:只写,文件不存在创建,文件存在清空
​ w+:可读可写,文件不存在创建,文件存在清空
​ a:追加(可写),文件不存在创建,存在追加
​ a+:可读可写,文件不存在创建,存在追加
​ 注:以"a"开头的附加模式下打开后续对该流操作总会写入文件末尾。
​ 返回值:成功:返回文件流指针
​ 失败:NULL
​ 关闭文件:
​ int fclose(FILE *fp);

/**

** Created by 24122 on 2022/4/28.

**/

练习:使用读写并且不存在创建存在清空权限,打开一个文件,然后关闭这个文件。

#include <stdio.h>

#include <stdlib.h>

#include <string.h>



int main(int argc, char *argv[])

{

FILE *fp;

fp = fopen("E:\\Code\\IOProcess\\1\\test.txt","w+");

if(fp == NULL)

{printf("fopen err\n");return -1;

}

fclose(fp);

return 0;

}

2.FILE *freopen

FILE *freopen(const char *pathname, const char mode, FILE fp)
功能:将指定的文件流指针重定向到打开的文件中
参数:path:文件路径
mode:打开文件的方式(同上)
fp:文件流指针
返回值:成功:返回文件流指针
失败:NULL

练习:打开一个文件并将标准输出重定向到这个文件,使用printf("hello world\n");来验证

/**

** Created by 24122 on 2022/4/28.

**/
#include <stdio.h>

int main(int argc, char *argv[])

{

freopen("E:\\Code\\IOProcess\\1\\test.txt","w",stdout);

printf("hello world!\n");

return 0;

}

补充:

	void perror(const char *s);
​	功能:当你调用“某些”函数出错时,会将参数 s 所指的字符串和错误的原因输出到标准设备。

char *strerror(int errnum);
功能:根据错误号返回错误原因字符串
参数:errnum:errno号

int fprintf(FILE *stream, const char *format, ...);
功能:向指定的流中输出数据
参数:
	stream:指定的文件流
	const char *format, ...:向流输入的内容
返回值:
	成功返回向文件流输入内容的字符个数
	失败返回0
练习1:指定一个文件,向这个文件输入hello world.
int main(int argc, char *argv[])                    
{                                                   
 	FILE *fp;
	fp = fopen("./test.txt","w");
	if(fp == NULL)
	{
		perror("fopen err");
		return -1;
	}
	fprintf(fp,"hello world\n");
	fclose(fp);
	return 0;                                       
}                                                   
练习2:测试一个进程最多可以打开多少个文件?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
    FILE *fp;
    int num = 0;
    while (1)
    {
        fp = fopen("./test.txt","r");
        if(fp == NULL)
        {
            break;
        }
        num++;
    }
    printf("num:%d",num);
    //printf("%p\n", fp);
    //fclose(fp);
    return 0;
}


【4】每次一个字符的读写:

1.int fgetc

int fgetc(FILE *stream);
功能:每次一个字符的读
参数:stream:文件流指针
返回值:成功:读到字符的ASCII
失败或文件结尾:EOF(-1)

2.int fputc

int fputc(int c, FILE *stream);
功能:向指定的文件中写一个字符
参数:c 要写的字符
stream 要写到的流
返回值:成功:写入的字符;
失败:EOF

练习:用fgetc和fputc实现cat的功能,从命令行输入文件名.
   
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *fp1,*fp2;
    //读取的文件
    fp1 = fopen(argv[1],"r");
    if(fp1 ==NULL)
    {
        perror("fopen err!\n");
        return -1;
    }
   fp2 = fopen(argv[2], "w");
   //实现cp
    /* if(fp2 ==NULL)
    {
       perror("fopen2 err!\n");
        return -1;
    }*/
    char temp;
    while ((temp= fgetc(fp1))!=EOF)
    {
        //fputc(temp, fp2);//实现cp
        fputc(temp, stdout);//实现cat
    }
    fclose(fp1);
    //fclose(fp2);
    return 0;
}

【5】每次一行的IO:

1.char *fgets

​ char *fgets(char *s, int size, FILE *stream);
​ 功能:从指定的流中读取最多size-1个字符,第size个字符是’\0’
​ 存放在s所指的空间
​ 参数:s 读到数据的存放位置
​ size 一次期望读到的数据,若遇到’\n’会直接返回
​ stream 流
​ 返回值:成功返回s的地址
​ 失败或读到文件结尾:NULL

2.int fputs

int fputs(const char *s, FILE *stream);
功能:向指定的文件流中写入一串字符
参数:s:要写入的字符内容
stream 流
返回值: 成功 实际写入的数据的个数
失败 EOF
注意:
fgets最多可以读size - 1个,最后一个字符必须是’\0’字符
fgets函数是每次读一行的函数,遇到’\n’字符返回

//练习1:用fgets实现wc –l的功能,文件名从命令行输入

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    int line =0;
    char buf[32];
    FILE *fp = fopen(argv[1],"r");
    if(fp ==NULL)
    {
        perror("fopen error!\n");
        return -1;
    }
    while (fgets(buf,sizeof (buf)-1,fp) != NULL)
    {
        if(buf[strlen(buf) - 1 ] == '\n')
        {
            line++;
        }
    }
    printf("%d %s", line, argv[1]);
    fclose(fp);
    return 0;
}
//练习2:用fgets和fputs实现cp的功能,两个文件名从命令行输入

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *fp1,*fp2;
    char buf[32];
    fp1 = fopen(argv[1], "r");
    fp2 = fopen(argv[2],"w");
    if(fp1 == NULL ||fp2 ==NULL)
    {
        perror("fopen error!\n");
        return -1;
    }
    while (fgets(buf,32,fp1) != NULL)
    {
        fputs(buf, fp2);
    }
    printf("cp complete!\n");
    fclose(fp1);
    fclose(fp2);
    return 0;
}
练习3:使用fgets从终端输入字符串,将此字符串写入指定文件里,当输入"quit"退出.

#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
    FILE *file1,file2;
    char buf[32] = {0};
    file1 = fopen(argv[1], "w");
    if(file1 ==NULL)
    {
        perror("fopen err");
        return -1;
    }
    while (1)
    {
        if(fgets(buf,sizeof (buf),stdin) == NULL)
        {
            perror("fgets err");
            return -1;
        }
        //printf("%s\n",buf);
        if(strcmp(buf,"quit\n")==0)
        {
            break;
        }
        /*if(strncmp(buf,"quit\n",4)==0)
        {
            break;
        }*/
        fputs(buf,file1);
    }
    fclose(file1);
    return 0;
}

【6】直接IO(二进制IO)

1.size_t fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);//从流里读
功能:从文件流读取多个元素
参数: ptr :用来存放读取元素的地址
size :元素大小 sizeof(数据类型)
nmemb :读取元素的个数
stream :要读取的文件
返回值:成功:读取的元素的个数;读到文件尾: 0
失败: -1

2.size_t fwrite(

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);//往流里写
功能:按对象写
参数:同上
返回值:成功:写的元素个数
失败 :-1

注意:
两个函数的返回值为:读或写的对象数
对于二进制数据我们更愿意一次读或写整个结构

//练习1:从一个文件中读取数据然后将数据往另外一个文件里去写

#include <stdio.h>
#include <string.h>

int main(int argc,char *argv[])
{
    FILE *fp1,*fp2;
    char buf ={0};
    fp1 = fopen(argv[1], "r");
    fp2 = fopen(argv[2], "w");
    if(fp1 == NULL)
    {
        perror("fopen err");
        return -1;
    }
    if(fread(buf,sizeof (char ),32,fp1) < 0)
    {
        perror("fread err");
        return -1;
    }
    if(fwrite(buf,sizeof (char ),strlen(buf),fp2) < 0)
    {
        perror("fwrite err");
        return -1;
    }
    printf("%s\n",buf);
    return 0;
}

【7】文件的偏移:

1.int fseek

​ int fseek(FILE *stream, long offset, int whence);
​ 功能:设定stream流的文件位置
​ 参数: stream 要偏移的流指针
​ offset 偏移量
​ 正数:向文件结尾位置移动 负数:向文件开始位置
​ whence 相对位置
​ SEEK_SET 开始位置
​ SEEK_CUR 当前位置
​ SEEK_END 结尾位置
​ 返回值:成功:0 失败:-1

2.long ftell(FILE *stream)

long ftell(FILE *stream);
功能:取得当前的文件位置
参数:要检测的流
返回值:当前的文件位置,出错则为-1L

3.void rewind

void rewind(FILE *stream);
功能:设定流的文件位置指示为文件开始

注意:rewind(fp)的功能和fseek(fp, 0, SEEK_SET)的功能相同

//练习:将指定文件的光标向后移动10个字节单位,并且写入一个字符

#include <stdio.h>

int main(int argc,char *argv[])
{
    FILE *fp;
    fp = fopen(argv[1], "w");
    if(fp ==NULL)
    {
        perror("fopen err");
        return -1;
    }
    fseek(fp, 10, SEEK_SET);
    fputc('a', fp);
    fclose(fp);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值