标准IO与文件IO(二)

目录

标准IO与文件IO

文件分类

基本分类

linux文件的操作

标准IO

文件打开操作

读取文件操作

int fgetc(FILE *stream)

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

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

写入文件

关闭----fclose()

使用相关函数复制任意大小的文件(包括图片)

二进制与文本

主函数参数

其他标准IO

fseek()

ftell()

rewind()

fprintf()

sprintf()

atoi() 字符串转整数

Lniux文件IO

与标准IO的区别:

缓存的分类

文件IO接口(系统调用)

打开 open

读取read

写入 write

close 关闭

lseek 定位函数

复制文件(文件io)

perror()

获取文件属性

stat()/fstat()/lstata()

目录操作函数

库的创建

静态库

动态库

标准IO与文件IO

IO就是针对文件的输入与输出

文件分类

基本分类

1、文本文件(ASCII码文件),文件中的内容是用ASCII码或者字符来显示的
2、二进制文件:文件当中存放的内容是二进制数据。
    两个文件在物理存储上没有差别(对于计算机来说都是二进制方式处理),逻辑有差别(文件的编码方式不同)
    linux系统文件分类:
        普通文件:-
        目录文件:d
        管道文件:p
        套接字文件:s
        链接文件:l
        块设备文件:b
        字符设备文件:c

linux文件的操作

标准IO

标准IO是由ANSI c标准提供的c语言标准函数库
    文件流:指数据像水流一样,所有的I/O操作仅是简单的从程序进或移除,这种字节流(比特流),就称为流。
    FILE* 是指文件指针类型,在类型指向是一个结构体,该结构体描述了文件相关信息,每一个应用程序会默认定义三个文件流指针:stdio stdout、stderr
    stdin:标准输入流
    stdout:标准输出流
    stderr:标准错误流
man手册:
    man 1:查看shell命令
    man 2:查看系统调用
    man 3:查看c标准库
​

文件打开操作

1、打开 -- fopen
FILE *fopen(const char *path, const char *mode);
path:表示文件路劲字符串
mode:打开文件的方式
    ”r“:只读打开,不会创建文件、文件流指针默认指向开头
    ”r+“:读写打开,不会创建文件、文件流指针默认指向开头
    “w”:只写打开,会创建文件(文件不存在时)或清空文件(文件存在),文件流指针默认指向开头
    “w+”:读写打开,会创建文件(文件不存在时)或清空文件(文件存在),文件流指针默认指向开头
    “a”:只写打开,会创建文件(文件不存在时)或追加内容(文件存在)。
    “a+”:读写打开,会创建文件(文件不存在时)或追加内容(文件存在)。
    ”b“:以二进制流方式,需要与前六个方式组合使用
返回值:
    NULL:表示错误返回
    正确返回文件指针流:该指针可以认为指向一个文件(path路径文件),因此利用该指针就可以间接操作文件。

读取文件操作

int fgetc(FILE *stream)

int fgetc(FILE *stream)
​
从指定文件中读取一个字符, 并且将字符返回. 
 stream: 返回值: 
 EOF:文件末尾 或 错误 
 正确返回当前读取的字符
 
​

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

char *fgets(char *s, int size, FILE *stream);//从指定文件读取一行,因为遇到‘\n’结束
​
意义: 从指定文件中读取一行数据. 当遇到'\n'表示一行读取结束. 
​
1.当size的值小于等于文件中一行数据的个数时, 读取的实际字符数是size-1,最后会默 认加一个'\0'
2.当size-1的值 大于 文件中一行数据的个数时,遇到'\n'正常结束. 并且读取到的内容 包含'\n' 
3.两种情况都必须以'\0'为结束标志. 
​
s: 数据首地址 
size: 想要读取一行文件内容的字节数 
stream: 文件流指针 
返回值: NULL: 错误返回 
正确返回数据首地址.
​
​
​
fgets只能用于读取文本文件(.txt),可能把其他字符认识成‘\n’。

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

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 
​
意义:按照指定的个数对文件进行数据读取.(这里的个数不是指字节数..) 
​
ptr: 数据首地址,可以为任意指针类型. 
​
size: 一个数据的字节大小 例子: 读取整数数据的话 size = sizeof(int) 
​
nmemb: 想要读取的数据个数. 
​
stream: 文件流指针 
​
返回值: 
​
错误 或 文件末尾: 0 或 比nmemb小的数字 
​
正确返回成功读取到的数据个数. 
​
​
因为fread函数不作错误返回还是结尾返回,如果要知道原因需要调用函数
判断出错或者是文件末尾可以使用以下函数(只有fread函数需要,只有读取需要判断): 
feof(): 判断是否到达文件末尾. 用法: if(foef(fp) != 0) ferror()://非零表示结尾退出
判断文件操作是否出错. 用法: if(ferror(fp) != 0)// 非零表示错误退出
​

写入文件

int fputc(int ch, FILE *stream):向文件写入一个字符. 
int fputs(const char *s, FILE *stream): 向文件写入一串数据. s表示数据的首地址. 
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); 
 
 返回值: 错误: 0 或 比nmemb小的数字 
 正确返回成功写入的数据个数. 

关闭----fclose()

int fclose(FILE *stream);
成功返回 0
失败返回    EOF
​
​

使用相关函数复制任意大小的文件(包括图片)

​
#include <stdio.h>
//FILE *fopen(const char *pathname, const char *mode)
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int main(int argc, char *argv[])
{ 
    if(argc != 3)
    {
        printf("Parameter error");
        return -1;
    }
    
    int buf[13] = {0};
    int ret;
    FILE* fd1 = fopen(argv[1],"r");
    if(NULL == fd1)
    {
        perror("why");
        return -1;
    }else{
        printf("%s open success\n",argv[1]);
    }
    
    FILE* fd2 = fopen(argv[2],"w+");
    if(NULL == fd2)
    {
        perror("why");
        return -1;
    }else{
        printf("%s open success\n",argv[2]);
    }
​
    while(1)
    {
        ret = fread(buf,sizeof(char),sizeof(buf),fd1);
        if(0 == ret)
        {
            if(ferror(fd1) != 0 )
            {
                perror("why");
                return -1;
            }else{
                printf("end of file\n");
                break;
            }
        }
        ret = fwrite(buf,sizeof(char),ret,fd2);
        if(0 == ret)
        {
            perror("why");
            return -1;
        }
    }
    fclose(fd1);
    fclose(fd2);
​
    return 0;
} 

二进制与文本

在物理结构上没有区别,因为存储在磁盘上都是以二进制存储。区别在逻辑上(编码不一样)。
Linux
{
换行符: ‘\n’
例如:abc‘\n’
文本:abc‘\n’
二进制:00110001 00110010 00110011 00001010
}
​
woinds
{
    '\r\n'相当于linux系统'\n'表示换行
    回车:'\r' 0x0d
    换行符:'\n' 0x0a
    文本方式:会被解释为一个字符'\n'
    二进制:会被解释层两个字符,正常读出
}
​
总结:在linux平台下,对文件操作时r与rb没区别
在wionds下有区别

主函数参数

int main(int argc, char * argv[])
{
    return 0;
}
argc:命令行参数个数
argv:指针参数,每一个元素指向每一个命令行参数。

命令行命令:eog 打开图片文件

其他标准IO

fseek()

fseek():可以修改文件的读写定位指针的指向位置。
​
int fseek(FILE *stream, long offset, int whence);
stream:文件指针
long offset:偏移量。可以是负数。
whence: SEEK_SET(头), SEEK_CUR(当前), SEEK_END(结尾)。
返回值:
成功 :0
失败: -1

ftell()

ftell(),默认当前位置
long ftell(FILE *stream);
返回当前文件流定位的位置,可以用于求文件大小。
    
求文件大小:
fseek(fd,0,SEEK_END);
ret = ftell(fd);

rewind()

rewind(),默认回到开头。
 void rewind(FILE *stream);

fprintf()

fprintf()//格式化的字符串写入文件函数,格式串写入指定文件
int fprintf(FILE *stream, const char *format, ...);

sprintf()

sprintf()格式化字符串函数,并将字符串存入指定地址空间
int sprintf(char *str, const char *format, ...);
根据自己的意愿产生字符串。

atoi() 字符串转整数

int atoi(const char *nptr);

Lniux文件IO

linux文件IO是linux系统提供的接口,所以又被称为系统调用。

与标准IO的区别:

c库函数是语言级函数,只要用c语言就可以用。系统调用由系统提供,跨系统就无法使用。标准IO带缓存,效率更高,大文件使用效率高。
标准IO
	1、接口是由c标准(ANSI C标准)提供的,与语言及程序有关。
	2、带缓存IO,又被称为高级IO。
	3、可用于所有普通文件的操作。

文件IO
	1、接口由操作系统(POSIX标准)提供,与操作系统有关。
	2、低级IO,不带缓存。
	3、linux系统下,有的特殊类型文件只能用文件IO操作,如:管道、设备文件等

缓存的分类

1、全缓存:对文件的读写,一般采用全缓存
	缓存区满、程序结束、fflush()函数。

2、行缓存:标准输入与标准输出采用的缓存方式
	刷新缓存区(缓存区数据写入文件stdout):遇到‘\n’、缓存区满、程序结束、fflush()函数。

3、无缓存:标准错误输出使用的方式
	没有刷新条件,有数据马上输出。
行缓存大小 1k
int main(int args, char **argv)  
{
    int i = 0;
    for (i = 0; i < 1025; ++i) /* 行缓存的边界值 1024:不能输出,i1025刚好可以输出*/
    {
    fprintf(stdout, "a");
    }
while (1);
}
​

全缓存大小 4k
int main(int args, char **argv)  
{
    FILE *fp = NULL;
​
    if ((fp = fopen("./a.txt", "w+")) == NULL) 
    {
        perror("19:fail to fopen");
        exit(EXIT_FAILURE);
        }
    putc('a', fp);  // 只有对文件进行读写操作了,buf才会为非0
    printf("IO_cache = %d\n",  fp->_IO_buf_end - fp->_IO_buf_base);
}
​

文件IO接口(系统调用)

打开 open

int creat(const char *pathname, mode_t mode);创建
int open(const char *pathname, int flags);只打开(文件必须不存在)
​
int open(const char *pathname, int flags, mode_t mode);创建并打开,需要指定第三个参数mode。(文件存在,要么清空,要么追加 flags)。
mode:设置文件的属性权限,使用八进制表示0664
pathname:文件路径名
flags:文件相关标志位,可以设置文件在程序中的读写权限
 三个必须有一个(O_RDONLY, O_WRONLY, or O_RDWR.)
 O_APPEND 以追加方式打开文件
 O_CREAT  以创建方式打开
 O—TRUNC  清空文件
 o_EXCL  检测文件是否已经存在与O_CREAT一起使用
 O_NONBLOCK or O_NDELAY 非阻塞
​
错误:-1
正常:返回描述符(非负整数),是操作文件的句柄
open()
​
​

读取read

ssize_t read(int fd, void *buf, size_t count);从fd中读取count大小的数据到buf
fd:文件描述符
buf:存储数据空间地址
count:读取字节数
返回值:
成功:
	1、大于零,返回读取字节数
	2、等于零,读到末尾
失败:
	-1

写入 write

 ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符
buf:存储数据空间地址
count:写入字节数

返回值:
成功:写入字节数
失败:-1

close 关闭

 int close(int fd);关闭文件
 成功:返回0
 失败:返回-1

lseek 定位函数

      off_t lseek(int fd, off_t offset, int whence);
成功:返回目前位置
失败:-1

复制文件(文件io)

​
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<string.h>
//int open(const char *pathname, int flags, mode_t mode);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
​
int main(int argc, char *argv[])
{ 
    char buf[13] = {0};
    int ret,ret2;
    int fd1 = open(argv[1],O_RDONLY);
    if(-1 == fd1)
    {
        perror("why");
    }else{
        printf("open %s success\n",argv[1]);
    }
​
    int fd2 = open(argv[2],O_WRONLY|O_CREAT|O_EXCL,0664);
    if(-1 == fd2)
    {
        perror("why");
    }else{
        printf("open %s success\n",argv[2]);
    }
​
    while(1)
    {
        ret = read(fd1,buf,13);
        if(-1 == ret)
        {
            perror("why");
            return -1;
        }else if(0 == ret)
        {
            printf("end if file\n");
            break;
        }else{
            printf("ret = %d\n",ret);
        }
​
        ret2=  write(fd2,buf,ret);
        if(-1 == ret2)
        {
            perror("why");
            return -1;
        }
        memset(buf,0,13);
    }
    close(fd1);
    close(fd2);
​
    return 0;
} 
​

perror()

perror():错误输出函数
void perror(const char *s) 
{
	意义: 函数内部会自动检测错误类型并且输出 错误原因.
}

获取文件属性

stat()/fstat()/lstata()

三个函数的意义都是获取文件相关属性
int stat(const char *path, struct stat *buf);
{
    该函数不能对链接文件进行处理。
    struct stat 结构体内部包含文件属性的描述
    path:文件路径
    返回值:
    出错:-1
    成功:0
}
​
int fstat(int fd, struct stat *buf);
{
    第一个参数需要传递文件描述符。
}
​
int lstat(const char *path, struct stat *buf);
{
    可以对链接文件进行处理。
}
​

目录操作函数

DIR *opendir(const char *name); 
{ 
    意义: 打开指定的目录. 
    返回值: 
         正确返回目录流指针.
         错误返回NULL
}
​
struct dirent *readdir(DIR *dirp);
{ 
    意义: 依次读取目录中的文件信息.
    返回值: 
        NULL: 读取到目录流末尾 或 产生错误. 
        正确返回一个 概述当前目录文件 的结构体.(struct dirent) 
}
​
    getpwuid()、根据id获取用户结构体
    getgrgid()、根据id获取用户主结构体
    localtime()与time()连用

库的创建

    可以看作是可执行文件的二进制形式,可以加载到内存运行
    1、将模块功能封装成库,可以便于移植、复用、共享
    2、保护源码、开放功能

静态库

1、是在编译阶段被链接
2、生成可执行文件体积较大(链接了静态库)
3、可执行文件的移植较方便(库已经链接好了)
    编译静态库
    {
        用法: ar 【选项】【libxx.a】【目标文件1】【目标文件2】....
            c: 创建一个库,不管以前是否已经存在.
            r: 替换库当中重名的、已经存在的模块. 
            s: 建立索引方式,可以快速查找库中的模块. 
    例如: ar crs libmy.a fun1.o fun2.o 
    
    编译使需要指明库的路径,使用 -L 与 -l来完成 
    例如: gcc test.c -L./ -lmyfun -L./day2/ -lmyfun2 
    -L: 表示需要链接库,后续跟库的路径 
    -l: 紧跟库的名字 名字不需要lib 也不需要.a
    }

动态库

1、是在运行阶段被链接. 
2、生成的可执行文件体积较小.
3、可执行文件的移植不方便(运行时需要库,所以还要移植库) 
编译动态库 
{
    用法: 
    先生成目标文件: gcc -c -fPIC fun.c 
    -fPIC: 创建与地址无关的编译程序.(表示当动态库里的模块被链接到程序中时,放在任意地址都 可以)
    动态库: gcc -shared -o libmyfun.so fun1.o fun2.o.. 
​
​
程序运行时链接动态库方式: 
        1、将动态库移动到/usr/lib 或 /lib下(注意: 避免覆盖系统自带的库)
        2、临时修改环境变量LD_LIBRARY_PATH=./ ./a.out 只在当前这一句有效. 
        3、添加/etc/ld.so.conf.d/*.conf文件,把库所在的路径加到文件末尾,并执行 ldconfig刷新• 这样,加入的目录下的所有库文件都可见. 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值