文件IO(input/output)
标准C文件I/O
fopen(打开文件)
-
函数原型
FILE *fopen(const char *path, const char *mode);
-
参数说明
path[入参] 将要打开的文件的路径
mode[入参] 文件打开方式
“r” 只读方式打开
“w” 只写方式打开,如果文件不存在,会新建,存在就清空
“r+” 可读可写方式打开,不清空,也不新建
“w+” 可读可写方式打开,清空,新建
“a+” 可读可写方式打开, 追加输入的方式,不清空,新建
入参: 输入参数(调用者传递给被调用者的值, 被调用者不能改), 带const的
出参: 输出参数(被调用者传递给调用者的值, 被调用者通常会改 参数值), 不带const
返回值 :
成功: 返回一个有效地址
失败: 返回 NULL -
返回值
返回值 :
成功: 返回一个有效地址
失败: 返回 NULL
-
使用例子
#include <stdio.h>
int main()
{
FILE *fp = fopen(“hello.c”, “r”);
if(fp != NULL)
{
printf(“open success\n”);
}
else
{
printf(“open failed\n”);
}
}
例2
#include <stdio.h>
int main()
{
FILE *fp = fopen(“hello1111.c”, “w”);
if(fp != NULL)
{
printf(“open success\n”);
}
else
{
printf(“open failed\n”);
}
}
fgetc(从文件中读出一个字符,必须先调用fopen)
fgetc 功能:从文件中读出一个字符,必须先调用fopen,然后才能读文件
int fgetc(FILE *stream);
参数: FILE *stream , fopen的返回值
返回值:
EOF 读失败, 否则,返回有效字符
char ch = fgetc(fp);
返回值:读出的字符
fgets(读取文件,每次读取一行)
fgets(读取文件,每次读取一行)
char *fgets(char *s, int size, FILE *stream);
参数1: char *s, 读出的数据存放的位置
2: 将要读出的数据的最大值(最多读多少个字符)
3: 文件指针
返回值:
NULL 读到了文件尾,或者读取失败
非NULL, 读取成功,返回读到数据存放的位置
fgets(buf, 100, fp);
#include <stdio.h>
int main()
{
FILE *fp = fopen(“hello.c”, “r”);
if(fp != NULL)
{
char buf[100] = { 0 };
while(fgets(buf, sizeof(buf), fp) != NULL)
{ //fgets 碰到 ‘\n’ 就读出此行,数据放到buf中
//如果一行多于 sizeof(buf), 最多读出sizeof(buf) - 1 个,因为最后一个是 ‘\0’
printf(“%s”, buf);
}
}
}
练习:统计文件行数
#include <stdio.h>
int main()
{
FILE *fp = fopen(“hello.c”, “r”);
if(fp != NULL)
{
int count = 0;
char buf[1000] = { 0 };
while(fgets(buf, sizeof(buf), fp) != NULL)
{
count++;
}
printf(“count is %d\n”, count);
}
}
fputs(往文件里写数据,写一行 ,和fgets正好相反)
fputs(功能:往文件里写数据,写一行) //和fgets正好相反
fputs(const char *s, FILE *stream);
参数 s, 是要写到文件中的数据存放位置
stream fopen的返回值
例: 从键盘输入5行,写到文件中
#include <stdio.h>
int main()
{
int i;
char buf[100] = { 0 };
FILE *fp = fopen(“cc.cc”, “w”);
if(fp != NULL)
{
for(i = 0; i < 5; i++)
{
char buf1[100] = { 0 };
scanf(“%s”, buf);
sprintf(buf1, “%s\n”, buf); //格式化输出 内容到 buf1中
fputs(buf1, fp);
}
fclose(fp);
}
}
fflush
fflush(fp); //强行将缓冲区中的数据写入文件
fread(读文件)
-
函数原型
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
-
参数说明
参数说明
ptr [出参]: 读出的数据,存入的位置
size : 一块的大小
nmemb : 将要读出的块数
stream : fopen的返回值 -
返回值
返回值:
实际读到的块数 (不是以字节为单位)
<= 0 读到了文件尾,或失败
int a[10];
fread(a, sizeof(int), 10, fp); //读出10个intchar a[100];
fread(a, sizeof(char), 100, fp); //读出100个char -
使用例子
//例子1次读1000字节//
#include <stdio.h>
int main()
{
char buf[1000] = { 0 };
FILE *fp = fopen(“hello.c”, “r”);
fread(buf, sizeof(char), sizeof(buf), fp);
printf(“%s”, buf);
}
//例子分批次读///
#include <stdio.h>
#include <string.h>
int main()
{
char buf[50] = { 0 };
FILE *fp = fopen(“hello.c”, “r”);
while(fread(buf, sizeof(char), sizeof(buf), fp) > 0)
{
printf(“%s”, buf);
memset(buf, 0, sizeof(buf));
}
}
130—>- 50
- 50
- 30 但是,buf中还剩20个上次读的数据
fwrite(写文件)
- 函数原型
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
-
参数说明
参数:
ptr 将要写入的数据的首地址
size 一块的大小
nmemb 将要写入块数
stream fopen的返回值 -
返回值
返回值: 实际写入的块数
int a[10] = {1,2,3,4,5,6,7,8,9,10};
fwrite(a, sizeof(int), 10, fp); //向文件中写入10个int
char buf[100] = “hello”;
fwrite(a, sizeof(char), 100, fp);文件分为两种类型
1 可以用记事本打开,并且不是乱码的,是可见字符,这种文件叫文本文件
hello.c
a.txt2 二进制文件,可执行文件,如果用记事本打开,是乱码
图片
可执行文件
word文件
/fwrite可以向文件中写入二进制数据 -
使用例子
///例子:将1,2,3,4,5,6,…,9 写入文件 write.c
#include <stdio.h>
int main()
{
int i;
FILE *fp = fopen(“cc.cc”, “w”);
for(i = 1; i < 10; i++)
{
fwrite(&i, sizeof(int), 1, fp); //写入一个int(4字节)
}
}
读出 read.c
#include <stdio.h>
int main()
{
int i, a[10] = { 0 };
FILE *fp = fopen(“cc.cc”, “r”);
int len = fread(a, sizeof(int), 10, fp);
printf(“len is %d\n”, len); //len ? 9
for(i = 0; i < 10; i++)
{
printf(“%d\n”, a[i]); //a ? 1,2,3,4,5,6,7,8,9,0
}
}
fseek(让文件指针到某个指定的位置)
-
函数原型
int fseek(FILE *stream, long offset, int whence);
-
参数说明
参数
stream fopen的返回值
offset(偏移量) 100 向后100字节 -100向前100字节
whence SEEK_END 到文件尾
SEEK_SET 到文件头
SEKK_CUR 到文件当前位置fseek(fp, -100, SEEK_END); // 文件指针指向 文件尾前100字节
fseek(fp, 100, SEEK_SET); // 文件指针指向 文件头后100字节
fseek(fp, 100, SEEK_CUR); // 文件指针指向 文件当前位置后100字节 -
使用例子
#include <stdio.h>
int main ()
{
char buf[10] = { 0 };
FILE *fp = fopen(“hello.c”, “r”);
if(fp != NULL)
{
fseek(fp, -10, SEEK_END);
fread(buf, 1, 10, fp);
printf(“%s”, buf);
}
}
fclose(关闭文件)
fclose(fp); 关闭文件,如果缓冲区中有数据,会将缓冲区中的数据强制写入文件
标准C文件I/O是带缓冲区机制的,缓冲区是Linux系统在打开文件时,自动新建的
如果文件打开失败,也不要关闭
Linux文件I/O
库文件
-
动态链接库
-
静态库
区别:
- 从占用内存及硬盘空间的角度
静态链接生成的可执行文件大,同时运行多份时,占用的内存多
动态链接生成的可执行文件小,运行多份时,只有一个库,占用内存少
2) 从 软件升级的角度
静态链接每个应用程序都需要升级
动态链接,只升级库函数即可 (更易于升级)- 从独立性的角度
静态链接好,不依赖于库 (如果看到有些可执行文件 50M 比较大,这种通常是静态链接)
结论: windows 和 linux系统的可执行文件多数都采用动态链接
动态链接一般需要安装文件 - 从占用内存及硬盘空间的角度
库函数
缓冲区机制
缓冲区机制:
一个快速设备 和 一个慢速设备通信 : 通常需要缓冲区
cpu(快速) 和 硬盘(慢速)进行通信, 需要由 内存导一下
//linux 输出(行缓冲输出 \n, + 全缓冲输出(够了 1024 字节,一起输出))
#include <stdio.h>
int main()
{
while(1)
{
printf(“hello”);
sleep(1); //延时1秒
}
}
默认缓冲区大小是1024字节
用fgets和fputs实现复制文件
cp a.c b.c //将a.c中数据写到b.c中
//./a.out a.c b.c
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc < 3)
{
printf(“param error, like this: ./a.out hello.c a.c\n”);
return -1;
}
FILE *fpr = fopen(argv[1], “r”);
if(fpr != NULL)
{
char buf[100] = { 0 };
FILE *fpw = fopen(argv[2], “w”);
while(fgets(buf, sizeof(buf), fpr) != NULL)
{
fputs(buf, fpw);
}
fclose(fpr);
fclose(fpw);
}
}
用fread和fwrite完成文件copy
练习:用fread 和 fwrite完成文件copy,
/分批次读///
#include <stdio.h>
int main(int argc, char *argv[])
{
if(argc < 3)
{
printf(“param error, like this: ./a.out a.c b.c\n”);
return -1;
}
FILE *fpr = fopen(argv[1], “r”);
if(fpr != NULL)
{
char buf[50] = { 0 };
int len;
FILE *fpw = fopen(argv[2], “w”);
while((len = fread(buf, sizeof(char), 50, fpr)) > 0)
{
fwrite(buf, sizeof(char), len, fpw);
}
fclose(fpr);
fclose(fpw);
}
}
XMind: ZEN - Trial Version