概述
访问文件方式(1)C库I/O函数;(2)系统调用I/O函数
1、C文件I/O接口库函数
标准C对I/O的概念进行抽象,对于C程序,所有的I/O操作就是移进、移出字节的事情,这种字节流被称为流。可以形象的认为流就是文件。C库函数读取、写入流基本都是完全缓冲,因为I/O函数和磁盘打交道速度太慢,所以就有了一个缓冲区,当缓冲区被塞满的时候,一起打包放入到文件或者设备。这就是完全缓冲。
1.文件常量
EOF:文件结束标志;FOPEN_MAX:程序最多打开文件个数;
2.文件I/O函数
功能 | 函数名 | 适用于 |
字符输入函数 | getchar | 标准输入流 |
字符输出函数 | putchar | 标准输出流 |
字符输入函数 | fgetc, getc | 所有输入流 |
字符输出函数 | fputc, putc | 所有输出流 |
文本行输入函数 | fgets, gets | 所有输入流 |
文本行输出函数 | fputs, puts | 所有输出流 |
格式化输入函数 | scanf | 标准输入流 |
格式化输出函数 | printf | 标准输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
3.打开流(文件)
参数介绍:参数1:文件的路径;
参数2:打开方式;
失败返回NULL;
打开方式介绍:
"r":在文件开始读文件
"r+":在文件开始处读和写
"w":如果文件存在则清空,否则创建文件
"w+":文件存在则清空文件,否则创建文件读和写
"a":如果文件不存在,创建文件并写入,否则在文件末尾写入
"a+":读和写,同上
"t":文本流
"b":二进制流
//程序事例
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp = fopen("./txt.txt","a+");
if(NULL == fp)
{
perror("fopen");
exit(1);
}
fclose(fp);
return 0;
}
4.字符I/O
//向标准输出写入
#include<stdio.h>
#include<stdlib.h>
int main()
{
int ch = 0;
do{
//ch = getchar();//从标准输入读取数据
//putchar(ch);//像标准输出输出数据
ch = getc(stdin);//可以理解为getchar对getc的封装
putc(ch,stdout);//putchar对putc的封装
}while(ch != EOF);
return 0;
}
//向文件写入
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp = fopen("./txt.txt","a+");
if(NULL == fp)
{
perror("fopen");
exit(1);
}
int ch = 0;
while((ch = getc(stdin)) != EOF)
{
putc(ch,fp);//向文件内写入
}
fclose(fp);
return 0;
}
//读取文件
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp = fopen("./txt.txt","r");
if(NULL == fp)
{
perror("fopen");
exit(1);
}
int ch = 0;
while((ch = getc(fp)) != EOF)
{
fputc(ch,stdout);
}
fclose(fp);
return 0;
}
5.未格式化的行I/O
未格式化:输入什么就是什么;
行:遇到 'n' 输出;
#include<stdio.h>
int main()
{
char str[128];
gets(str);//从标准输入读
puts(str);//向标准输出写入
return 0;
}
注:fgets如果读取到文件尾(EOF)或者读取错误返回NULL;
//实现一个记事本
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp = fopen("./txt.txt","a+");
if(NULL == fp)
{
perror("fopen");
exit(1);
}
char line[128];//缓冲区
while(1)
{
line[0] = 0;//清空缓冲区
fgets(line,sizeof(line),stdin);
if(strcmp(line,"quitn") == 0)
break;
fputs(line,fp);//把缓冲区内容写入文件
}
fclose(fp);
return 0;
}
6.格式化的行I/O
scanf格式:
#include<stdio.h>
int main()
{
//char buf[8] = {0};
//scanf("%4s",buf);//限制buf输入的字符个数为4个
//printf("%sn",buf);
//int i = 0;
//scanf("%x",&i);//输入1234
//printf("%#xn",i);//输出0x1234 十六进制
int a = 0;
scanf("%o",&a);
printf("%#on",a);
//八进制:
//%o 1234
//%#o 01234
return 0;
}
printf格式:
#include<stdio.h>
int main()
{
printf("%c %c n",'a',65);
printf("%d %ldn",1977,650000L);
printf("[%10d] n",1977); //10个位置右对齐
printf("[%-10d]n",1977); //10个位置左对齐
printf("%010d n",1977); //右对齐,左边的空格用0补全
printf("%d %x %#x %o %#o n",100,100,100,100,100);
// %x 十六进制 1234
// %#x 0x1234
// %o 八进制 1234
// %#o 01234
printf("%4.2f n",3.1486); //4表示预留多少个位置(包含小数点),2表示小数点后有几位,会四舍五入
printf("[%*d] n",5,10);//5就是*,表示有五个位置,d就是10
printf("%s n","hello world");
return 0;
}
///
a.out
a A
1977 650000
[ 1977]
[1977 ]
0000001977
100 64 0x64 144 0144
3.15
[ 10]
hello world
int main()
{
char buf[100];
float f = 0;
FILE *fp = fopen("./txt.txt","w+");
if(NULL == fp)
{
strerror(errno);
exit(1);
}
fprintf(fp,"%f %s",3.1416,"helloworld");//字符串不可以有空格,不然空格后面字符串输不出来
rewind(fp);//使光标回到文件开头
fscanf(fp,"%f",&f);
fscanf(fp,"%s",buf);
fclose(fp);
printf("%f %sn",f,buf);
return 0;
}
7.二进制I/O (二进制读写“rb”,“wb”等)
//二进制I/O读取结构体向文件
#include<stdio.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
typedef struct A{
int a;
int b;
char c;
char str[20];
}A;
int main()
{
FILE *fp = fopen("./txt.txt","a+b");
if (NULL == fp)
{
perror("fopen");
exit(1);
}
A x = { 1, 2, 'a', "hello world" };
//fwrite(&x, 1, sizeof(x), fp); //向文件写入结构体
A y;
fread(&y, 1, sizeof(y), fp); //从文件读取结构体
fclose(fp);
return 0;
}
返回值:若成功,返回0;若失败非0值
该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值
下面两个程序都是获取文件大小
//获取文件大小
int main()
{
FILE *fp = fopen("./txt.txt","a+b");
if (NULL == fp)
{
perror("fopen");
exit(1);
}
int total = 0;
int count = 0;
char buf[100] = { 0 };
while (!feof(fp)) //光标没有到达文件尾返回0,否则非0
{ //二进制读取文件只能用feof来判断是否到达文件尾,而文本流可以feof也可以EOF
buf[0] = 0;
count = fread(buf, 1, sizeof(buf), fp);//返回实际读取到多少,只有这么用,返回值才表示真正读取到多少字节
if (ferror(fp) != 0)//如果错误,他会对于返回错误码,0是正确
{
perror("fp");
exit(1);
}
total += count;
}
printf("total = %d n", total);
fclose(fp);
return 0;
}
//获取文件大小
int main()
{
FILE *fp = fopen("./txt.txt","a+b");
if (NULL == fp)
{
perror("fopen");
exit(1);
}
long total = 0;
int ret = fseek(fp, 0, SEEK_END);
if(ret != 0)
{
perror("fseek");
exit(2);
}
total = ftell(fp);
if(total == -1L)
{
perror("ftell");
exit(3);
}
printf("total = %d n", total);
fclose(fp);
return 0;
}
int main()
{
FILE *fp_1 = fopen("scr_txt.txt", "a+");
char buf[128] = { 0 };
//给源文件写入
while (1)
{
buf[0] = 0;
fgets(buf,sizeof(buf),stdin);
if (strcmp(buf, "quitn") == 0)
break;
fputs(buf, fp_1);
}
fclose(fp_1);
//把源文件内容拷贝到目标文件
fp_1 = fopen("scr_txt.txt", "a+b");
FILE *fp_2 = fopen("dst_txt.txt", "a+b");
if (!fp_1 || !fp_2)
{
perror("fopen");
exit(1);
}
while (!feof(fp_1))
{
buf[0] = 0;
size_t ret = fread(buf, 1, sizeof(buf), fp_1);
if (ferror(fp_1) != 0)
{
perror("fp_1");
exit(3);
}
fwrite(buf, ret, 1, fp_2);//把fp_2改为stdout,输出到标准输出
if (ferror(fp_2) != 0)
{
perror("fp_2");
exit(4);
}
}
fclose(fp_1);
fclose(fp_2);
return 0;
}
//文件内容拷贝
int main()
{
FILE *fp_1 = fopen("./scr_txt.txt", "a+b");
if (NULL == fp_1)
{
perror("fp_1");
exit(1);
}
FILE * fp_2 = fopen("./dst_txt.txt", "a+b");
if (fp_2 == NULL)
{
perror("fp_2");
exit(2);
}
fseek(fp_1, 0, SEEK_END);
long scr_size = ftell(fp_1);
char *buf = (char *)malloc(scr_size);
assert(buf);
rewind(fp_1);
fread(buf, scr_size, 1, fp_1);
fwrite(buf, scr_size, 1, fp_2);
free(buf);
fclose(fp_1);
fclose(fp_2);
return 0;
}
2.系统文件I/O接口函数 (基本不带缓冲)
除了上面c库函数接口,还有系统调用接口。常用的就是5个函数:open、read、write、lseek以及close。
1.文件描述符
对于内核而言,所有对文件的操作都通过文件描述符来操作,文件描述符是一个小的非负整数,当打开或者创建一个文件,内核都会向进程返回一个文件描述符。读和写一个文件时,使用的文件描述符参数就是open返回值。其实,当我们创建一个文件,就会对应创建一个数据结构来描述该目标文件,于是就有了文件结构体,open打开文件,为了使得文件和进程关联起来,在进程task_struct里面的I/O相关信息里面有个文件描述符指针,指向一个文件描述表就是数组,每个元素就是对该文件的属性描述,而数组下标就是文件描述符,大多是操作系统默认文件描述符0是标准输入,1是标准输出,2是标准错误。
文件描述符分配规则:从文件描述符表下标0开始查找,空闲的下标,作为当前文件的文件描述符(如果我们不关闭0,1,2,一般文件描述符从3开始)。
当我们一直打开文件,而不关闭文件,就会导致文件描述符越来越大,当然有上限,就会导致打开文件失败。其实,文件描述符最大多少可以调整,输入指令ulimit -a,进行对应修改。
2.open函数
当我们打开一个文件,除非有O_APPEND选项 当前文件偏移量从文件尾开始,否则是从文件开始处。
3.close函数
4.lseek函数
下面程序是求文件大小:前面讲讲到的,还有下面的,一共三种方法获取文件大小
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
int fp = open("./txt.txt",O_RDONLY);
if(fp<0)
{
perror("open");
exit(1);
}
off_t total = lseek(fp,0,SEEK_END);
if(total<0)
{
perror("lseek");
exit(2);
}
close(fp);
printf("total = %ldn",total);
return 0;
}
5.read函数和write函数
下面程序是从标准输入读取,并且标准输出 (ctrl +d结束)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
char buf[1024] = {0};
int n = 0;
while((n = read(0,buf,sizeof(1024)-1)) >0)
{
if(write(1,buf,n) != n)
{
perror("write");
exit(1);
}
}
if(n<0)
{
perror("read");
exit(2);
}
return 0;
}
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
int fd = open("./txt.txt",O_WRONLY);
if(fd<0)
{
perror("open");
exit(1);
}
char buf[128] = {0};
while(fgets(buf,sizeof(buf)-1,stdin)) //ctrl+d结束
{
long size = strlen(buf);
if(write(fd,buf,size)!= size)
{
perror("write");
exit(2);
}
buf[0] = 0;
}
close(fd);
return 0;
}
下面程序实现拷贝文件内容
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
int main()
{
int scr_fd = open("./txt.txt",O_RDONLY);
if(scr_fd<0)
{
perror("open");
exit(1);
}
int dst_fd = open("./scr.txt",O_CREAT|O_WRONLY);
if(dst_fd<0)
{
perror("open");
exit(2);
}
ssize_t n = 0;
char buf[10] = {0};
while((n = read(scr_fd,buf,sizeof(buf)-1))>0)
{
if(write(dst_fd,buf,n) != n)
{
perror("write");
close(scr_fd);
close(dst_fd);
exit(3);
}
}
if(n<0)
{
perror("read");
close(scr_fd);
close(dst_fd);
exit(4);
}
close(scr_fd);
close(dst_fd);//可以使用goto语句,可以少些close
return 0;
}
最后
以上就是懵懂小虾米为你收集整理的I/O接口库函数和系统调用I/O接口函数的全部内容,希望文章能够帮你解决I/O接口库函数和系统调用I/O接口函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复