Linux软件编程----标准IO

目录

IO:输入输出

1.标准IO 

2.特殊的流 

3.缓存:

    1.全缓存  

    2.行缓存    

    3.不缓存    

4.函数接口

    1.fopen

    2.fclose

    3.setvbuf 

    4.fputc

    5.fgetc 

    6.fgets

    7.fputs 

    8.fscanf

    9.fprintf

    10.fread

    11.fwrite



IO:输入输出


    操作对象:文件

Linux系统一切皆是文件:
            文件分类:
            1.block          b    块设备文件       按块扫描设备信息的文件
            2.char           c     字符设备文件   按字符扫描设备信息的文件 
            3.directory    d     目录文件          保存或管理文件
            4.                  -      普通文件          保存数据信息的文件(代码、图片、音视频、压缩包等)
            5.link             l      链接文件          指向其他文件的文件(类似与window系统的快捷方式) 
            6.socket       s      套接字文件      用于进程间通信 
            7.pipe           p     管道文件          用于进程间通信

1.标准IO 


    stdio.h  
    主要操作普通文件 ,步骤如下。
            1.打开文件 :fopen
            2.读写文件 :fgetc/fputc、fgets/fputs、fscanf/fprintf、fread/fwrite
            3.关闭文件 :fclose

2.特殊的流 

    默认打开的流(不需要fopen手动打开的流)
    stdin       标准输入流           行缓存
    stdout      标准输出流          行缓存
    stderr      标准错误流          不缓存

    这三个流是默认和终端(显示屏,键盘等)建立的流

        

    gets、getchar、scanf是基于stdin实现的
    puts、putchar、printf是基于stdout实现的 
    perror是基于stderr

3.缓存:

这里我们发现,./a.out的时候并没有打印hello world,因为我们交给库函数之后,要先缓存,当在hello world后面加\n的时候,就会打印出来,因为这是行缓存刷新的标志。


    1.全缓存  

                 4096  (4k) 
                缓存区满刷新
        
                与文件建立的缓存一般为全缓存

                刷新条件:
                    1.缓存区存满了刷新
                    2.fflush函数接口刷新

                                fflush(文件流)

                        
                    3.关闭流时会刷新(fclose)

                                flcose(文件流)

                        

                全缓存遇到\n,不会刷新。

    2.行缓存    

                1024  (1k)
                遇到\n刷新 

                与终端建立的缓存都是行缓存

        刷新条件: 
                    1.缓存区满刷新 
                    2.遇到\n刷新 
                    3.fflush函数刷新 
                    4.关闭流时会刷新

    3.不缓存    

        0  0k
        立即刷新 

        刷新条件:
                    1.立即刷新

                    1.对设备的操作不允许缓存(鼠标,键盘等)
                    2.通信不允许缓存
                    3.出错处理不缓存 

4.函数接口


    1.fopen

 
              FILE *fopen(const char *pathname, const char *mode);
      功能:
                打开pathname对应的文件并建立一个文件流(方向性,连续性)
      参数:
                pathname:文件路径
                mode:打开方式
                    r      只读             如果文件存在则只读打开
                                            如果文件不存在报错
                    r+     读写             如果文件存在则读写打开
                                            如果文件不存在报错
                    w      只写             如果文件存在则清0,只写打开 
                                            如果文件不存在则创建
                    w+     写读             如果文件存在则清0,读写打开 
                                            如果文件不存在则创建
                    a      追加只写         如果文件存在则追加只写打开 
                                            如果文件不存在则创建
                    a+     追加读写         如果文件存在则追加读写打开 
                                            如果文件不存在则创建
      返回值:
                成功返回FILE*的指针(所以要定义一个FILE类型的指针去接收返回的指针
                失败返回NULL并且将错误码置位 

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;   //定义一个指针去接受返回的指针

    fp = fopen("a.txt", "r");  //打开当前目录下的a.txt,只读的方式
    if (NULL == fp)
    {
        perror("打开 a.txt 文件失败");  //perror会显示打开失败的原因
        return -1;
    }                          //判断是否打开失败

    return 0;
}

    2.fclose

        只打开不关闭会造成内存泄漏
              int fclose(FILE *stream);
      功能:   
                关闭流 
      参数: 
                stream:文件流
      返回值:
                成功返回0 
                失败返回EOF(-1)

    3.setvbuf 


              int setvbuf(FILE *stream, char *buf, int mode, size_t size);
      功能:
                改变流的缓存类型
      参数:
                stream:文件流
                buf:缓存区的首地址 
                mode:   
                            _IOFBF  全缓存(块缓存,文件流的时候)
                            _IOLBF  行缓存(终端的时候)
                            _IONBF  不缓存
                size:缓存区大小
      返回值:
                成功返回0 
                失败返回非0 

#include <stdio.h>

int main(void)
{
    char tmpbuff[4096] = {0}; //全缓存内存为4K,所以定义一个4k大小的缓存区。

#if 0
    setvbuf(stdout, tmpbuff, _IOFBF, 4096);
    printf("stdout被切换为全缓存\n");  //改变为全缓存,这时候运行不会打印

    setvbuf(stdout, NULL, _IONBF, 0);
    printf("stdout被切换为不缓存\n");  //改变为不缓存,这时候运行有\n的会被打印,没有的也会打印
#endif

    setvbuf(stdout, tmpbuff, _IOLBF, 1024); //改编为行缓存,这时候运行有\n的会被打印,没有不会打印

    printf("hello world!\n");
    while (1)
    {

    }                //while循环是为了不让代码结束这样才能看到全缓存的效果

    return 0;
}

    4.fputc


             int fputc(int c, FILE *stream);
      功能:
                向流中写入一个字符
      参数:
                c:写入的字符(这里可以直接写字符,也可以写指针所指向的字符(*p就是这字符))
                stream:文件流指针
      返回值:
                成功返回写入字符的ASCII码值
                失败返回EOF(-1) 

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    char ch = 'A';

    /* 打开文件 */
    fp = fopen("a.txt", "w");//接收文件的地址
    if (NULL == fp)
    {
        perror("fopen a.txt failed");
        return -1;
    }

    /* 读写文件 */
    fputc('a', fp);
    fputc(ch, fp);
    fputc(ch+32, fp);

    /* 关闭文件 */
    fclose(fp);

    return 0;
}

结果就会给a.txt写入:

    练习:
              1.编写程序利用fputc将"hello world"写入到file.txt文件中

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    char str[32] = {"hello world"};
    char *p = str;

    fp = fopen("file.txt", "w");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    while (*p != '\0')//字符串的结尾就是\0,p是指针,*p就是指针指向的内容
    {
        fputc(*p, fp);
        p++;
    }//用循环将所有的字符全部写入

    fclose(fp);

    return 0;
}

    5.fgetc 


              int fgetc(FILE *stream);
      功能:
                从流中读取一个字符 (定义一个整型的变量去接收,因为返回值是ascii码)
      参数:
                stream:文件流指针
      返回值:
                成功返回读到字符的ASCII码值(所以接收数据的变量定义为int型)。
                失败或者读到文件末尾返回EOF

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    int ch = 0;//因为返回的是ASCII的值,所以定义为int型

    fp = fopen("file.txt", "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    while (1)
    {
        ch = fgetc(fp);
        if (EOF == ch)//失败或者读到末尾返回EOF
        {
            break;
        }
        printf("%c", ch);//因为是自动获取下一个所以不需要地址跳转下一个地址的代码
    }

    fclose(fp);

    return 0;
}

输出的结果如下,和cat一样,所以cat的实现方式也是这样的。

需要注意的是:

fgetc不会重复的获取,获取完一个会自动跳到下一个。所以用一个fgetc,然后循环会接收到不同的字符。

    等价
    ch = getchar();//在终端中得到字符
    ch = fgetc(stdin);//在stdin文件流中得到字符

    putchar(ch);//给终端输入字符
    fputc(ch, stdout);//给stdout文件流输入字符

   
    
作业:
1.编写一个程序将a.txt文件中的所有内容拷贝到b.txt文件中 

#include <stdio.h>
#include "software.h"

int main(void)
{
    char srcfile[256] = {0};
    char dstfile[256] = {0};
    int ret = 0;

    printf("请输入源文件路径:\n");
    gets(srcfile);
    printf("请输入目的文件路径:\n");
    gets(dstfile);

    ret = CopyAsciiFileContent(dstfile, srcfile); 
    if (-1 == ret)
    {
        printf("拷贝内容失败\n");
    }
    
    printf("拷贝内容成功\n");

    return 0;
}
#include "software.h"
#include <stdio.h>

/***************************************************
 * 函数名:CopyAsciiFileContent
 * 功  能:
 *      将srcfile中的文件内容拷贝到dstfile文件中
 * 参  数:
 *      dstfile:目的文件的文件路径
 *      srcfile:源文件的文件路径
 * 返回值:
 *      成功返回0 
 *      失败返回-1 
 * 注意事项:
 *      1.该函数只能拷贝ASCII普通文件内容
 **************************************************/
int CopyAsciiFileContent(const char *dstfile, const char *srcfile)
{
    FILE *fsrc = NULL;
    FILE *fdst = NULL;
    int temp = 0;

    fsrc = fopen(srcfile, "r");
    if (NULL == fsrc)
    {
        goto err2;
    }

    fdst = fopen(dstfile, "w");
    if (NULL == fdst)
    {
        goto err1;
    }

    while (1)
    {
        temp = fgetc(fsrc);
        if (EOF == temp)
        {
            break;
        }
        fputc(temp, fdst);
    }

    fclose(fsrc);
    fclose(fdst);

    return 0;

err1:
    fclose(fsrc);
err2:
    return -1;
}
#ifndef __SOFTWARE_H__
#define __SOFTWARE_H__

extern int CopyAsciiFileContent(const char *dstfile, const char *srcfile);

#endif

2.编写一个程序,从终端输入文件名,统计出该文件内容(纯英文)中出现频率最高的字符及其出现次数
    a.txt 

#include <stdio.h>

int GetMaxFreqChar(const char *filename, char *pmaxchar, int *pmaxcnt)
{
    FILE *fp = NULL;
    int temp = 0;
    int cnt[256] = {0};
    int max = 0;
    int i = 0;

    fp = fopen(filename, "r");
    if (NULL == fp)
    {
        return -1;
    }

    while (1)
    {
        temp = fgetc(fp);
        if (EOF == temp)
        {
            break;
        }
        cnt[temp]++;   
    }
    
    fclose(fp);

    max = 0;
    for (i = 0; i < 256; i++)
    {
        if (cnt[i] > cnt[max])
        {
            max = i;
        }
    }

    if (0 == cnt[max])
    {
        return -1;
    }

    *pmaxchar = max;
    *pmaxcnt = cnt[max];

    return 0;
}

int main(void)
{
    char filename[256] = {0};
    char maxchar = 0;
    int maxcnt = 0;
    int ret = 0;

    printf("请输入文件名:\n");
    scanf("%s", filename);

    ret = GetMaxFreqChar(filename, &maxchar, &maxcnt);
    if (-1 == ret)
    {
        printf("查找出错\n");
        return -1;
    }

    printf("出现频率最高的字符:%c , 共出现 %d 次\n", maxchar, maxcnt);

    return 0;
}

    6.fgets

               char *fgets(char *s, int size, FILE *stream);
       功能:
                 从流中读取一行字符串(遇到\n就会停止,并且会把\n也存起来,最后末尾会自动加\0表示字符串的结尾) 遇到\0也停止。
       参数:
                  s:用于存放读取到的字符串
                  size:字符串的长度(最大可以存放的数,不是要接收多少,遇到\n就会停止)
                  stream:文件流指针
       返回值: 
                 成功返回存放字符串空间首地址(所以要定义一个指针去接收返回的值,来判断是否接收成功)
                 失败或者读到文件末尾返回NULL

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    char *pret = NULL;
    char tmpbuff[4096] = {0};

    fp = fopen("file.txt", "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    while (1)
    {
        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);
        if (NULL == pret)
        {
            break;
        }
        printf("%s", tmpbuff);//不加\n,是因为读取会把原有的\n也加上
    }

    fclose(fp);

    return 0;
}

注意:这里的sizeof(tmpbuff)是最大可以存放的数,不是要接收多少。

在文本文件取字符串之后的情况如下:左文本,右存放的地方

假如sizeof(tmbuff)的大小为5个,那么实际的读取4个,因为要在末尾留一个\0的位置。

    7.fputs 

              int fputs(const char *s, FILE *stream);
      功能:
                向流中写入一个字符串( 遇到\0停止)
      参数:
                s:字符串的首地址
                stream:文件流指针 
      返回值: 
                成功返回非负数
                失败返回EOF

        

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    char tmpbuff[1024] = {"how are you"};

    fp = fopen("file.txt", "w");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fputs("hello world", fp);
    fputs(tmpbuff, fp);

    fclose(fp);

    return 0;
}

练习:利用fgets和fputs实现将一个文件中的内容拷贝到另一个文件中

#include <stdio.h>
/***************************************************
 * 函数名:CopyAsciiFileContent2
 * 功  能:
 *      将srcfile中的文件内容拷贝到dstfile文件中
 * 参  数:
 *      dstfile:目的文件的文件路径
 *      srcfile:源文件的文件路径
 * 返回值:
 *      成功返回0 
 *      失败返回-1 
 * 注意事项:
 *      1.该函数只能拷贝ASCII普通文件内容
 **************************************************/
int CopyAsciiFileContent2(const char *dstfile, const char *srcfile)
{
    FILE *fsrc = NULL;
    FILE *fdst = NULL;
    char tmpbuff[4096] = {0};
    char *pret = NULL;

    fsrc = fopen(srcfile, "r");
    if (NULL == fsrc)
    {
        goto err1;
    }

    fdst = fopen(dstfile, "w");
    if (NULL == fdst)
    {
        goto err2;
    }

    while (1)
    {
        pret = fgets(tmpbuff, sizeof(tmpbuff), fsrc); 
        if (NULL == pret)
        {
            break;
        }
        fputs(tmpbuff, fdst);
    }

    fclose(fsrc);
    fclose(fdst);

    return 0;

err2:
    fclose(fsrc);
err1:
    return -1;
}

int main(void)
{
    char srcfile[256] = {0};
    char dstfile[256] = {0};
    int ret = 0;

    ret = CopyAsciiFileContent2("a.txt", "stdio.h"); 
    if (-1 == ret)
    {
        printf("拷贝内容失败\n");
    }
    
    printf("拷贝内容成功\n");

    return 0;
}

注意:

    puts(tmpbuff); 
    fputs(tmpbuff, stdout);
    puts会多打印一个\n字符

    gets(tmpbuff);
    fgets(tmpbuff, sizeof(tmpbuff), stdin);
    gets会去掉用户输入\n字符,并加上\0,也就是把\n换成\0。 
    fgets不会去掉用户输入的\n字符,并且在末尾再加个\0。

 

那么fgets怎么将\n换成\0呢?

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

int main(void)
{
    char tmpbuff[1024] = {0};

    gets(tmpbuff);
    printf("tmpbuff = %s\n", tmpbuff);

    fgets(tmpbuff, sizeof(tmpbuff), stdin);
    tmpbuff[strlen(tmpbuff)-1] = '\0';//去掉fgets接受的\n,强行转为\0.
    printf("tmpbuff = %s\n", tmpbuff);

#if 0
    puts("hello world");
    fputs("hello world", stdout);
#endif
    return 0;
}

结果如下:

    8.fscanf

            int fscanf(FILE *stream, const char *format, ...);
    功能:
                从流中读取格式化字符串
    
            fscanf(stdin, ...);
            scanf(...);

    返回值:

                返回值是一个整型。

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    int num1 = 0;
    int num2 = 0;

    fp = fopen("file.txt", "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fscanf(fp, "num1 = %d, num2 = %d", &num1, &num2);

    fclose(fp);

    printf("num1 = %d, num2 = %d\n", num1, num2);    

    return 0;
}

文件中的格式:

 注意:fscanf目标文件的内容的时候,格式必须和文件里的内容一致,使用起来比较繁琐。就和scanf类似一样,代码写成啥格式,在终端输入的时候也要用一样的格式输入,

    9.fprintf

            int fprintf(FILE *stream, const char *format, ...);
    功能:
                向流中写入格式化字符串

    参数:

                stream:文件流指针 
                ... :是可变参函数。

     返回值:

                成功返回实际打印的字节数。

                失败返回-1。

​
#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    int num1 = 100;
    int num2 = 200;

    fp = fopen("file.txt", "w");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fprintf(fp, "hello world\nnum1 = %d, num2 = %d\n", num1, num2);

    fclose(fp);

    return 0;
}

​

结果如下:

如下俩个等价:

        fprintf(stdout, ...);
        printf(...);

练习:
            将score.csv中每个学生的成绩获得平均值逐行写入到avg.csv中

#include <stdio.h>

int main(void)
{
    FILE *fsrc = NULL;
    FILE *fdst = NULL;
    int score1 = 0;
    int score2 = 0;
    int score3 = 0;
    double avgscore = 0;
    int ret = 0;

    fsrc = fopen("score.csv", "r");
    if (NULL == fsrc)
    {
        perror("fail to fopen");
        return -1;
    }

    fdst = fopen("avg.csv", "w");
    if (NULL == fdst)
    {
        perror("fail to fopen");
        fclose(fsrc);
        return -1;
    }

    while (1)
    {
        ret = fscanf(fsrc, "%d,%d,%d", &score1, &score2, &score3);
        if (EOF == ret)
        {
            break;
        }
        avgscore = (score1 + score2 + score3) / 3.0;
        fprintf(fdst, "%.2lf\n", avgscore);
    }
    
    fclose(fsrc);
    fclose(fdst);

    return 0;

技巧:在使用fprintf和fscanf的时候,可以先像写printf和scanf的时候的格式写,之后在补充目标文件流。

    10.fread

        可以操作二进制文件,图片,压缩包等,前面的都是ascii码文件。

        ascii中的一个字节一个字节的存放,2对应的ascii码的大小为48,48在二进制中为00110010。ascii码文件是一种特殊的二进制文件。

        二进制文件2024是以整体的形式,也就是整型,4个字节,一个字节8位,总共32位。

              size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
      功能:
                从流中读取nmemb个对象,每个对象size个字节,在ptr指向的空间中存放
      参数:
                ptr:存放数据空间的首地址
                size:每个对象的大小
                nmemb:写入对象的个数
                stream:文件流指针
      返回值: 
                成功返回实际读取对象的个数(最好用size_t 类型的变量接收)
                失败或者读到文件末尾返回0 

#include <stdio.h>

typedef struct student 
{
    char name[32];
    char sex;
    int age;
    int score;
}stu_t;

int main(void)
{
    FILE *fp = NULL;
    stu_t temp;
    stu_t s[4];
    int i = 0;
    size_t nret = 0;

    fp = fopen("file.txt", "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    nret = fread(s, sizeof(stu_t), 4, fp);//一次性读4组。
    for (i = 0; i < nret; i++)//这里接收到多少也就是nret,就循环多少次。
    {
        printf("姓名:%s\n", s[i].name);
        printf("性别:%c\n", s[i].sex);
        printf("年龄:%d\n", s[i].age);
        printf("成绩:%d\n", s[i].score);
    }
#if 0
    while (1)
    {
        nret =fread(&temp,sizeof(stu t),1, fp);//一次性读1组,读4次。
        if(0 == nret)
        {
            break;
        }
        printf("姓名:%s\n"temp.name);
        printf("性别:名c\n",temp.sex);
        printf("年龄:%d\n",temp.age);
        printf("成绩:%d\n",temp.score);
    }
#endif
    fclose(fp);

    return 0;
}

    11.fwrite

              size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
      功能:
                向流中写入nmemb个对象,每个对象size个字节,要写入的内容在ptr指向的空间中存放
      参数:
                ptr:写入数据空间的首地址
                size:每个对象的大小
                nmemb:写入对象的个数
                stream:文件流指针
      返回值: 
                成功返回实际写入对象的个数,返回类型位size_t类型。
                失败返回0 

#include <stdio.h>

typedef struct student 
{
    char name[32];
    char sex;
    int age;
    int score;
}stu_t;

int main(void)
{
    FILE *fp = NULL;
    stu_t a = {"张三", 'm', 19, 100};
    stu_t b = {"李四", 'f', 18, 90};
    stu_t s[2] = {
        {"王二", 'm', 16, 90},
        {"赵五", 'f', 14, 30},
    };
    size_t nret = 0;

    fp = fopen("file.txt", "w");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    nret = fwrite(&a, sizeof(a), 1, fp);
    printf("nret = %ld\n", nret);
    nret = fwrite(&b, sizeof(b), 1, fp);
    printf("nret = %ld\n", nret);
    nret = fwrite(s, sizeof(stu_t), 2, fp);
    printf("nret = %ld\n", nret);

    fclose(fp);

    return 0;
}

首先写入的是结构体的大小

第二个char是一个字节,要内存对齐,所以空出来3个字节。

所以总共占176个字节。

一次性写入多个内容,那么要把写入的内容放在一起,也就是类似上面s[2]一个数组可以有多个内容,因为fwrite的地址只有一个。fwrite(s, sizeof(stu_t), 2, fp);

作业:
        1.从终端输入一个单词,打印出该单词的含义

练习:
1.利用fread和fwrite实现文件的拷贝
      char tmpbuff[4096];
      图片的拷贝

#include <stdio.h>

int main(void)
{
    FILE *fsrc = NULL;
    FILE *fdst = NULL;
    size_t nret = 0;
    char tmpbuff[4096] = {0};

    //打开源文件
    fsrc = fopen("src.jpg", "r");
    if (NULL == fsrc)
    {
        perror("fail to fopen");
        return -1;
    }

    //打开目的文件 
    fdst = fopen("dst.jpg", "w");
    if (NULL == fdst)
    {
        perror("fail to fopen");
        fclose(fsrc);
        return -1;
    }

    while (1)
    {
        nret = fread(tmpbuff, 1, sizeof(tmpbuff), fsrc);//每次读一个对象,读sizeof大小个。
        if (0 == nret)
        {
            break;
        }
        fwrite(tmpbuff, 1, nret, fdst);
    }
    
    fclose(fsrc);
    fclose(fdst);

    return 0;
}

12.fseek

   流的定位
            偏移量:读和写都在偏移量的位置进行
    int fseek(FILE *stream, long offset, int whence);
            功能:
                        设置流的偏移量
            参数:
                        stream:文件流指针
                        offset:偏移量 
                        whence:
                                    SEEK_SET        文件开头
                                    SEEK_CUR        当前位置
                                    SEEK_END        文件结尾
              返回值:
                        成功返回当前偏移量
                        失败返回-1 

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;

    fp = fopen("file.txt", "w");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fseek(fp, 10, SEEK_SET);
    fputc('a', fp);

    fseek(fp, -5, SEEK_CUR);
    fputc('b', fp);

    fseek(fp, 0, SEEK_SET);
    fputc('c', fp);

    fclose(fp);

    return 0;
}

结果如下:

od -c file.txt是以字符的形式展现

   13.ftell

        long ftell(FILE *stream);
    功能:
                获取流的偏移量 

  返回值:

                整型的偏移量
   如下利用ftell, 通过偏移量获得文件的大小。

​
#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    long len = 0;

    fp = fopen("/usr/include/stdio.h", "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fseek(fp, 0, SEEK_END);
    len = ftell(fp);
    printf("len = %ld\n", len);

    fclose(fp);

    return 0;
}

​

    14.rewind


    void rewind(FILE *stream);
    功能:
                将流的偏移量重新设置到开头

    fseek(fp, 0, SEEK_SET);

练习:
编写程序随便给定一个bmp图片文件名获得图片的宽度和高度

#include <stdio.h>

int main(void)
{
    FILE *fp = NULL;
    int width = 0;
    int height = 0;

    fp = fopen("suibian.bmp", "r");
    if (NULL == fp)
    {
        perror("fail to fopen");
        return -1;
    }

    fseek(fp, 18, SEEK_SET);//存储文件大小的信息在18个字节之后,所以偏移18。
    fread(&width, 4, 1, fp);  //宽度占4字节,储存的类型是long类型,是二进制形式,所以要用fread。
    fread(&height, 4, 1, fp);  //高度占4字节

    fclose(fp);

    printf("宽度:%d 高度:%d\n", width, height);

    return 0;
}

5.单词查询

用strncmp,strcmp+strtok,指针

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

int GetWordMean(const char *pfilename, char *pword, char *pmean)
{
    FILE *fp = NULL;
    char *pret = NULL;
    int isexist = 0;
    char tmpbuff[4096] = {0};
    char *ptmp = NULL;

    fp = fopen(pfilename, "r");
    if (NULL == fp)
    {
        return -1;
    }

    while (1)
    {
        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);
        if (NULL == pret)
        {
            break;
        }

#if 0
        if (0 == strncmp(tmpbuff, pword, strlen(pword)))   //读取一行,比较单词是否相同,相同则复制到pmean。
        {
            strcpy(pmean, tmpbuff);
            isexist = 1;
            break;
        }

        if (0 == strcmp(pword, strtok(tmpbuff, " ")))  //strtok的使用。
        {
            strcpy(pmean, strtok(NULL, "\r"));
            isexist = 1;
            break;
        }
#else
        ptmp = tmpbuff;
        while (*ptmp != '\0' && *ptmp != ' ')
        {
            ptmp++;
        }
        *ptmp = '\0';
        ptmp++;

        if (0 == strcmp(pword, tmpbuff))
        {
            while (*ptmp == ' ' && *ptmp != '\0')
            {
                ptmp++;
            }
            strcpy(pmean, ptmp);
            isexist = 1;
            break;
        }
#endif
    }

    fclose(fp);

    return isexist;
}

int main(void)
{
    char word[256] = {0};
    char mean[1024] = {0};
    int ret = 0;

    printf("请输入一个单词:\n");
    fgets(word, sizeof(word), stdin);
    word[strlen(word)-1] = '\0';

    ret = GetWordMean("dict.txt", word, mean);
    if (-1 == ret)
    {
        printf("查找出错\n");
    }
    else if (0 == ret)
    {
        printf("未找到\n");
    }
    else if (1 == ret)
    {
        printf("%s 含义: %s\n", word, mean);
    }

    return 0;
}

用内核链表

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

/* 定义链表节点类型 */
typedef struct word 
{
    struct list_head node;          //节点
    char word[256];                 //单词
    char mean[1024];                //含义
}word_t;

int GetWordMean(const char *pfilename, char *pword, char *pmean)
{
    FILE *fp = NULL;
    char *pret = NULL;
    int isexist = 0;
    char tmpbuff[4096] = {0};

    /* 创建一个节点并对节点初始化 */
    struct list_head head;
    INIT_LIST_HEAD(&head);

    fp = fopen(pfilename, "r");
    if (NULL == fp)
    {
        return -1;
    }

    while (1)
    {
        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);
        if (NULL == pret)
        {
            break;
        }
        
        /* 申请一个节点,存入数据,插入链表中 */
        word_t *ptmp = malloc(sizeof(word_t));  //用word_t tmp是局部变量,会被回收,所以要用malloc来申请一个空间。
        if (NULL == ptmp)
        {
            return -1;
        }
        strcpy(ptmp->word, strtok(tmpbuff, " "));
        strcpy(ptmp->mean, strtok(NULL, "\r"));    //存入数据
        list_add_tail(&ptmp->node, &head);        //插入到链表中
    }

    fclose(fp);

    /* 查找单词 */
    struct list_head *ptmp = NULL;  //定义一个指针去遍历
    list_for_each(ptmp, &head)
    {
        if (0 == strcmp(pword, ((word_t *)ptmp)->word))
        {
            strcpy(pmean, ((word_t *)ptmp)->mean);
            isexist = 1;
            break;
        }
    }

    /* 销毁链表中所有已存在的节点 */
    list_for_each(ptmp, &head)
    {
        struct list_head *p = ptmp->prev;
        list_del(ptmp);
        free(ptmp);
        ptmp = p;
    }

    return isexist;
}

int main(void)
{
    char word[256] = {0};
    char mean[1024] = {0};
    int ret = 0;

    printf("请输入一个单词:\n");
    fgets(word, sizeof(word), stdin);
    word[strlen(word)-1] = '\0';

    ret = GetWordMean("dict.txt", word, mean);
    if (-1 == ret)
    {
        printf("查找出错\n");
    }
    else if (0 == ret)
    {
        printf("未找到\n");
    }
    else if (1 == ret)
    {
        printf("%s 含义: %s\n", word, mean);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值