linux库函数io文件操作函数

1. fopen()

1. 头文件:
stdio.h
2. fopen的原型:
FILE *fopen(const char *filename, const char *mode);
3. 返回值:
fopen 返回指向打开文件的文件指针,若出错则返回NULL(空指针)。
4. 参数:
其两个参数均为字符串。
第一个参数filename
第一个参数为打开文件的文件名,
文件名由 路径+主文件名+扩展名组成
例如 /home/ol/Desktop/lianxi/std_io_test + file_handler_txt + .txt
若使用fopen时省略这个参数的路径,则默认为这个项目所在路径。
第二个参数mode
第二个参数为打开模式具体如表
序号文件使用方式当指定文件存在时候当指定文件不存在的时候用法1“r”仅供读取报错1.w/w+相当于创建文件,再进行写入/读写
2.a/a+相当于w的不清空,并且文件指针自动偏移到文件的结尾
3.二进制和文本文件目前没区别
2"w"清空后,仅供写入创建文件
3"a"追加,仅供写入创建文件
4"r+"读取和写入报错
5"w+"清空文件,读取和写入创建文件
6"a+"追加,读取和写入创建文件rb/wb/ab加b和不加一样目前不考虑对二进制进行操作。

1. “r” 无文件打开,报错。有文件就可以读取。

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

void test_file_r(void)
{
    FILE *file = fopen("./file_hander_test.txt", "r");
    if (file == NULL)
    {
        LOG_DBG("file fopen fail:%s", strerror(errno));
        return;
    }
    else
    {
        LOG_DBG("file fopen success");
    }

    fclose(file);
    return;
}

int main()
{
    test_file_r();
    return 0;
}

无文件,就报错。

2. “w” 无文件就创建。有文件就清空再开始写,不支持读出。

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

typedef struct test_st_type
{
    char a;
    int b;
    char c;
}test_st;

void test_file_write_or_read(void)
{
    test_st fwrite_value[4] = {{0,1,2}, {3,4,5}, {6,7,8}, {0,0,0}};
    test_st fread_value[3] = {0};

    FILE *file = fopen("./file_hander_test.txt", "w");
    if (file == NULL)
    {
        LOG_DBG("file fopen fail:%s", strerror(errno));
        return;
    }
    else
    {
        LOG_DBG("file fopen success");
    }

    int ret_fwrite = fwrite(fwrite_value, sizeof(fwrite_value), 3, file);
    printf("ret_fwrite:%d\r\n", ret_fwrite);

    int ret_fread = fread(fread_value, sizeof(fread_value), 2, file);
    printf("ret_fread:%d\r\n", ret_fread);
    printf("fread_value[0], a:%d, b:%d, c:%d\r\n", fread_value[0].a, fread_value[0].b, fread_value[0].c);
    printf("fread_value[1], a:%d, b:%d, c:%d\r\n", fread_value[1].a, fread_value[1].b, fread_value[1].c);

    fclose(file);
    return;
}

int main()
{
    test_file_write_or_read();
    return 0;
}

无文件就创建文件,写入之后,也不可读出。

3. “a” 无文件就创建。有文件就追加写。

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

void test_file_r(void)
{
    FILE *file = fopen("./file_hander_test.txt", "r");
    if (file == NULL)
    {
        LOG_DBG("file fopen fail:%s", strerror(errno));
        return;
    }
    else
    {
        LOG_DBG("file fopen success");
    }

    fclose(file);
    return;
}

void test_file_w(void)
{
    FILE *file = fopen("./file_hander_test.txt", "w");
    if (file == NULL)
    {
        LOG_DBG("file fopen fail:%s", strerror(errno));
        return;
    }
    else
    {
        LOG_DBG("file fopen success");
    }

    fclose(file);
    return;
}

void test_file_a(void)
{
    FILE *file = fopen("./file_hander_test.txt", "a");
    if (file == NULL)
    {
        LOG_DBG("file fopen fail:%s", strerror(errno));
        return;
    }
    else
    {
        LOG_DBG("file fopen success");
    }

    fclose(file);
    return;
}

int main()
{
    //test_file_r();
    //test_file_w();
    test_file_a();
    return 0;
}

2. fclose()

1. fclose的原型:
int fclose(FILE *stream);
2. 返回值:
该函数返回一个整型数。当文件关闭成功时, 返回0, 否则返回一个非零值
3. 参数:
由fopen()函数返回的句柄参数stream,传入fclose()
4. 用法:
fclose()函数用来关闭一个由fopen()函数打开的文件 , 其调用格式为fclose(stream)可以根据函数的返回值判断文件是否关闭成功。

3. fwite()

1. fwrite的原型:
size_t fwrite(const void * buf, size_t size, size_t count, FILE *fp);
2. 返回值 :
size_t 返回的是实际写入到文件的 基本单元 个数 ;
3. 参数 :
const void *buf : 指针指向要写入数据的内存首地址 ;
size_t size : 要写入数据的 基本单元 的字节大小 ;
size_t count : 要写入数据的 基本单元 的个数 ;
FILE * fp : 打开的文件指针 ;
4. 用法:
向打开的文件里面写入数据。

4. fread()

1. fread的原型:
size_t fread(void *buf, size_t size, size_t count, FILE *fp);
2. 返回值 :
size_t 实际从文件中读取的 基本单元 个数 ; 读取的字节数是 基本单元个数 * 基本单元字节大小 ;
3. 参数:
void *buf 参数 : 将文件中的数据读取到该缓冲区中 ;
size_t size 参数 : 读取的 基本单元 字节大小 , 单位是字节 , 一般是 buffer 缓冲的单位大小 ;
如果 buffer 缓冲区是 char 数组 , 则该参数的值是 sizeof(char) ;
如果 buffer 缓冲区是 int 数组 , 则该参数的值是 sizeof(int) ;
size_t count 参数 : 读取的 基本单元 个数 ;
FILE * fp 参数 : 文件指针 ;
4. 用法:
向打开的文件里面读取数据。

5. fseek()

1. fseek的原型:
int fseek(FILE* stream, long offset, int whence);
2. 返回值:
当调用成功时则返回0, 若有错误则返回-1, errno 会存放错误代码.
3. 参数:
stream 为已打开的文件指针,
参数offset 为根据参数whence 来移动读写位置的位移数。
参数 whence 为下列其中一种:
SEEK_SET 将读写位置指向文件开头,再增加offset 个位移量.
SEEK_CUR 将读写位置指向文件当前位置,再增加offset 个位移量.
SEEK_END 将读写位置指向文件末尾,再增加offset 个位移量.

当whence 值为SEEK_CUR 或 SEEK_END 时, 参数offset 允许负值的出现.
下列是较特别的使用方式:
1.欲将读写位置移动到文件开头时:
fseek(FILE *stream, 0, SEEK_SET);
2.欲将读写位置移动到文件尾时:
fseek(FILE *stream, 0, SEEK_END);
4. 用法:
用来移动文件流的读写位置,fseek()不像lseek()会返回读写位置, 因此必须使用ftell()来取得目前读写的位置.

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

typedef struct test_st_type
{
    char a;
    int b;
    char c;
}test_st;

void test_file_write_or_read(void)
{
    test_st fwrite_value[4] = {{0,1,2}, {3,4,5}, {6,7,8}, {0,0,0}};
    test_st fread_value[3] = {0};

    FILE *file = fopen("./file_hander_test.txt", "w+");
    if (file == NULL)
    {
        LOG_DBG("file fopen fail:%s", strerror(errno));
        return;
    }
    else
    {
        LOG_DBG("file fopen success");
    }

    int ret_fwrite = fwrite(fwrite_value, sizeof(fwrite_value), 3, file);
    printf("ret_fwrite:%d\r\n", ret_fwrite);
    //fflush(file);

    fseek(file, 0, SEEK_SET);

    int ret_fread = fread(fread_value, sizeof(fread_value), 2, file);
    printf("ret_fread:%d\r\n", ret_fread);
    printf("fread_value[0], a:%d, b:%d, c:%d\r\n", fread_value[0].a, fread_value[0].b, fread_value[0].c);
    printf("fread_value[1], a:%d, b:%d, c:%d\r\n", fread_value[1].a, fread_value[1].b, fread_value[1].c);

    fclose(file);
    return;
}

int main()
{
    test_file_write_or_read();
    return 0;
}

6. ftell()

1. ftell的原型:
long ftell(FILE *stream);
2. 返回值:
返回当前文件位置
3. 参数:
stream 为已打开的文件指针。
4. 用法:
ftell()用于得到文件指针当前位置相对于文件首的偏移字节数.
利用函数 ftell() 能方便地知道一个文件的长。
如以下语句序列: fseek(fp, 0L, SEEK_END); len =ftell(fp); 首先将文件的当前位置移到文件的末尾,然后调用函数ftell()获得当前位置相对于文件首的位移,该位移值等于文件所含字节数。
前提条件:因为 ftell() 返回long型,根据long型的取值范围-231~231-1(-2147483648~2147483647),故对大于2.1G的文件进行操作时出错。

7. fflush()

1. fflush的原型:
int fflush(FILE *stream)
2. 返回值:
如果成功刷新,fflush返回0。指定的流没有缓冲区或者只读打开时也返回0值。返回EOF指出一个错误。
3. 参数:
stream 为已打开的文件指针。
3. 用法:
清除读写缓冲区,在需要立即把输出缓冲区的数据进行物理写入时,调用。

8. snprintf() 格式化字符串函数

1. snprintf的原型:
int snprintf(char *str, size_t size, const char *format, …)。
2. 返回值:
(1) 如果格式化后的字符串长度小于 size,则会把字符串全部复制到 str 中,并给其后添加一个字符串结束符 \0;
(2) 如果格式化后的字符串长度大于等于 size,超过 size-1 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0,
返回值为欲写入的字符串长度。
3. 参数:
str – 目标字符串。
size – 拷贝字节数(Bytes),长度包含\0。
format – 格式化成字符串。
… – 可变参数。
4. 用法:
把输入的字符串,按照输入的格式format,进行初始化后,输入到str。

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

void test_string_hander(void)
{
    char buf_a[16];
    int ret_a = snprintf(buf_a, sizeof(buf_a), "%s%d%s", "xiao6", 10, "liang");//5+2+5=12
    printf("buf_a:%s, ret_a:%d, sizeof(buf_a):%d\r\n", buf_a, ret_a, sizeof(buf_a));
    //buf_a:xiao610liang, ret_a:12, sizeof(buf_a):16

    char buf_b[8];
    int ret_b = snprintf(buf_b, sizeof(buf_b), "a123456789");
    printf("buf_a:%s, ret_b:%d, sizeof(buf_b):%d\r\n", buf_b, ret_b, sizeof(buf_b));
    //buf_a:a123456, ret_b:10, sizeof(buf_b):8
}

int main()
{
    test_string_hander();    
    return 0;
}

总结:
1.snprintf的返回值n,当调用失败时,n为负数,当调用成功时,n为格式化的字符串的总长度(不包括\0),当然这个字符串有可能被截断,因为buf的长度不够放下整个字符串。
1.snprintf会自动在格式化后的字符串尾添加\0,所以buf里面装的数据肯定包含一个\0。
2.snprintf会在结尾加上\0,不管buf空间够不够用,所以不必担心缓冲区溢出。

可以判断输出
if ( n < 0) : snprintf出错了
if ( n >0 && n < sizeof(buf) ) : snprintf成功,并且格式了完成的字符串。
if ( n >= sizeof(buf) ) : snprintf成功,但要格式化的字符串被截断了。

9. sscanf() 解析并转换字符串函数

1. sscanf的原型:
int sscanf(const char *str, const char *format, …);
2. 返回值:
成功则返回参数数目,失败则返回-1,错误原因存于errno中。返回0表示失败,否则,表示正确格式化数据的个数
3. 参数:
str:待解析的字符串;
format:字符串格式描述;
其后是一序列数目不定的指针参数,存储解析后的数据.
4. 用法:
描述sscanf通常被用来解析并转换字符串,其格式定义灵活多变,可以实现很强大的字符串解析功能。

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

void test_string_hander(void)
{
    char buf_a[16];
    int ret_a = snprintf(buf_a, sizeof(buf_a), "%s%d%s", "xiao6", 10, "liang");
    printf("buf_a:%s, ret_a:%d, sizeof(buf_a):%d\r\n", buf_a, ret_a, sizeof(buf_a));
    //buf_a:xiao610liang, ret_a:12, sizeof(buf_a):16

    char buf_b[8];
    int ret_b = snprintf(buf_b, sizeof(buf_b), "a123456789");
    printf("buf_a:%s, ret_b:%d, sizeof(buf_b):%d\r\n", buf_b, ret_b, sizeof(buf_b));
    //buf_a:a123456, ret_b:10, sizeof(buf_b):8
}

void test_string_sscanf(void)
{
    //整形数转换
    int year, month, day;
    int converted_int = sscanf("20191103", "%04d%02d%02d", &year, &month, &day);
    printf("converted_int=%d, year=%d, month=%d, day=%d\r\n", converted_int, year, month, day);
    // 输出结果:
    // converted=3, year=2019, month=11, day=03
    // "%04d%02d%02d"是用来解析字符串的格式,%表示格式转换的开始,d表示转换为一个整数,04作为d的修饰,表示这是一个长度为4位的整数,不足4位时以0补齐。
    // 例子返回结果等于3,表示有3个数据成功转换,转换成功数目同时取决于被解析的字符串以及其转换格式,如果我们把例子中的格式改为"%04d%02d",那么sscanf将只返回2,day的数值不会被sscanf更改。

    //浮点数转换
    double longitude, latitude;
    int converted_double = sscanf("113.123456789 31.123456789", "%lf %lf", &longitude, &latitude);
    printf("converted_double=%d, longitude=%.9lf, latitude=%lf\r\n", converted_double, longitude, latitude);
    // 输出结果:
    // converted=2, longitude=113.123456789, latitude=31.123457
    // sscanf的格式字符串中,f表示这是一个浮点数,其修饰词l表示这是一个double的浮点数。
}

int main()
{
    //test_string_hander();
    test_string_sscanf();
    return 0;
}
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "share.h"

void test_string_sscanf(void)
{
    //整形数转换
    int year, month, day;
    int converted_int = sscanf("20191103", "%04d%02d%02d", &year, &month, &day);
    printf("converted_int=%d, year=%d, month=%d, day=%d\r\n", converted_int, year, month, day);
    // 输出结果:
    // converted=3, year=2019, month=11, day=03
    // "%04d%02d%02d"是用来解析字符串的格式,%表示格式转换的开始,d表示转换为一个整数,04作为d的修饰,表示这是一个长度为4位的整数,不足4位时以0补齐。
    // 例子返回结果等于3,表示有3个数据成功转换,转换成功数目同时取决于被解析的字符串以及其转换格式,如果我们把例子中的格式改为"%04d%02d",那么sscanf将只返回2,day的数值不会被sscanf更改。

    //浮点数转换
    double longitude, latitude;
    int converted_double = sscanf("113.123456789 31.123456789", "%lf %lf", &longitude, &latitude);
    printf("converted_double=%d, longitude=%.9lf, latitude=%lf\r\n", converted_double, longitude, latitude);
    // 输出结果:
    // converted=2, longitude=113.123456789, latitude=31.123457
    // sscanf的格式字符串中,f表示这是一个浮点数,其修饰词l表示这是一个double的浮点数。
}

void test_string_high_sscanf()
{
    //使用[]过滤出数字
    char str_a[32] = "";
    sscanf("1234abcd", "%2[0-9]d", str_a);
    printf("str_a=%s\r\n", str_a);
    // 输出结果 str_a=1234

    //使用[]过滤出数字
    char str_1[32] = "";
    sscanf("1234abcd", "%31[0-9]", str_1);
    printf("str_1=%s\r\n", str_1);
    // 输出结果:str_1=1234
    // 上面的格式中,[0-9]表示这是一个仅包含0-9这几个字符的字符串,前面使用数字31修饰词表示这个字符串缓冲区的最大长度(这也是sscanf最为人诟病的地方,
    // 很容易出现缓冲区溢出错误,实际上sscanf是可以避免出现缓冲区溢出的,只要在书写任何字符串解析的格式时,注意加上其缓冲区尺寸的限制)。

    //使用[]过滤出数字和字母
    char str_2[32] = "";
    sscanf("1234abcd", "%31[0-9a-z]", str_2);
    printf("str_2=%s\r\n", str_2);
    // 输出结果:str_2=1234abcd
    // 在格式[]中增加了a-z的描述。

    // 使用^ 过滤不包含的数据:
    char str_3[32] = "";
    sscanf("1234abcd", "%31[^a-z]", str_3);
    printf("str_3=%s\r\n", str_3);
    // 输出结果:str_3=1234
    // 在[]中增加表示相反的意思,上面的[a-z]表示一个不包含任何a-z之间的字符串。

    //使用* 忽略数据:
    char str_4[32] = "";
    int ret_4 = sscanf("1234abcd", "%*[0-9]%31[a-z]", str_4);
    printf("ret_4=%d, str_4=%s\r\n", ret_4, str_4);
    // 输出结果:ret_4=1, str_4=abcd
    // 加上*修饰表示一个被忽略的数据,同时也不需要为它准备空间存放解析结果。如上面的例子中,我们就只使用了str一个参数存放%31[a-z]的解析结果,而sscanf也只返回1,表示只解析了一个数据。

    //使用[]取不同的数据
    char str_5[32] = "";
    char str_6[32] = "";
    int ret_5 = sscanf("1234abcd", "%[0-9]%31[a-z]", str_5, str_6);
    printf("ret_5=%d, str_5=%s, str_6=%s\r\n",ret_5, str_5, str_6);
    // 输出结果:ret_5=2, str_5=1234, str_6=abcd
    //返回值2表示成功解析了2个数据,str_5解析出了数字,str_6解析出了字母

}

int main()
{
    //test_string_hander();
    //test_string_sscanf();
    test_string_high_sscanf();
    return 0;
}

有需要再来研究复杂的吧!!!!

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值