【标准IO】
[1]FILE *fopen(const char *path,const char *mode)
功能:打开文件
参数:path:打开文件的路径
mode:打开方式
r 只读,流被定位到文件开头
r+ 可读可写,流被定位到开头
w 只写,文件不存在创建,存在清空,流被定位到文件开头
w+ 可读可写,文件不存在创建,存在清空,流被定位到文件开头
a 追加,文件不存在创建,存在追加,流被定位到文件末尾
a+ 可读可写,文件不存在创建,存在追加;第一次读文件时流被定位到文件开头,写始终在末尾
#include
int main(int argc, char const *argv[])
{
FILE *fp;//创建一个文件指针
fp = fopen("./hello.c","a+");//文件指针指向hello.c文件,并以可读可写追加的形式打开
if(NULL == fp)//容错判断:当fp为空(指向文件失败时)时返回-1
{
perror("fopen error");
return -1;
}
else
printf("fopen success\n");//容错判断:当fp不为空(指向文件成功时)时,提示语句
//while(1);
return 0;
}
[2]int fgetc(FILE *stream)
功能:从文件中读取一个字符
参数:stream:文件流
返回值:
成功:读到字符的ASCII码
失败或读到文件末尾:EOF
[3]int fputc(int c,FILE *stream)
功能:向文件中写入一个字符
参数:c:要写的字符
stream:文件流
返回值:成功:写的字符的ASCII
失败:EOF
[2][3]演示
练习:通过fgets函数实现“wc -l 文件名”命令。(计算文件行数)
要求:./可执行程序 文件名
#include
#include
int main(int argc, char const *argv[])
{
FILE *fp = fopen(argv[1], "r");
if (NULL == fp)
{
printf("fp指向%s文件失败\n", argv[1]);
return -1;
}
printf("fp指向%s文件成功\n", argv[1]);
char buf[32] = {0};
char a = 0;
while ((a = fgetc(fp)) != EOF)
{
printf("%c", a);
}
printf("%d\n", a);
fclose(fp);
return 0;
}
[4]int feof(FILE *stream)
功能:判断文件有没有到达结尾
返回:到达结尾,返回非零值
[5]int ferror(FILE *stream)
功能:检测文件有没有出错
返回:文件出错,返回非零值
[6]char * fgets(char*s ,int size,FILE *stream)
功能:从文件中每次读取一行字符串
参数:
s:存取字符串的地址
size:一次读取的字符个数
stream:文件流
返回值:
成功:s的地址
失败或读到文件末尾:NULL
特性:每次实际读到的字符个数为size-1,会在末尾自动添加\0,遇到\n结束一次读
[7]int fputs(const char *s,FILE *stream)
功能:向文件中写字符串
参数:
s:要写的内容
stream:文件流
返回值:
成功:非负整数
失败:EOF
[2][3][6][7]演示
#include
int main(int argc, char const *argv[])
{
FILE *fp = fopen(argv[1],"a+");//打开a.out后所输入的一个文件,文件不存在即创建,存在即清空后再指向
if(NULL == fp)
{
perror("fp指向错误\n");
return -1;
}
else
printf("fp指向%s成功\n",argv[1]);//指向成功则打印
#if 1
char ch;
ch = fgetc(fp);//从fp指向的文件里复制开头第一个字符给ch
printf("%c\n",ch);
ch = fgetc(fp);
printf("%c\n",ch);
fputc('a',fp);//向fp指向的文件开头写入一个字符'a'
fclose(fp);//关闭fp指向的文件
#endif
#if 0
char buf[32] = {0};
fgets(buf,32,fp);//从缓冲区的流指针里读取32位大小的char类型buf
printf("%s\n",buf);
//char buf[32] = {0};
printf("请输入>");
fgets(buf,32,stdin);//从终端的标准输入里输出32位大小的char类型buf
printf("输出:%s\n",buf);
fputs(buf,fp);//把buf内容写给fp所指向的文件
fputs(buf,stdout);
#endif
return 0;
}
[6][7]练习
通过fgets函数实现“wc -l 文件名”命令。(计算文件行数)
通过fgetc实现cat功能。cat 文件名 --> ./a.out 文件名
思路:打开文件,循环读文件,(fgetc返回值 EOF)输出,关闭
#include
#include
int main(int argc, char const *argv[])
{
//1.打开文件
FILE *fp = fopen(argv[1], "r");
if (NULL == fp)
{
perror("fopen err");
return -1;
}
printf("fopen succ\n");
//2.循环读(判断)
char buf[32] = {0};
int len = 0;
while (fgets(buf, 32, fp) != NULL)
{
if (buf[strlen(buf) - 1] == '\n')
len++;
}
printf("%d %s\n", len, argv[1]);
//3.关闭
fclose(fp);
return 0;
}
[1~7]练习
1、 通过fgetc实现cat功能。cat 文件名 --> ./a.out 文件名
思路:打开文件,循环读文件,(fgetc返回值 EOF)输出,关闭
#include
#include
int main(int argc, char const *argv[])
{
FILE *fp = fopen(argv[1], "r");
if (NULL == fp)
{
printf("fp指向%s文件失败\n", argv[1]);
return -1;
}
printf("fp指向%s文件成功\n", argv[1]);
char buf[32] = {0};
char a = 0;
while ((a = fgetc(fp)) != EOF)
{
printf("%c", a);
}
printf("%d\n", a);
fclose(fp);
return 0;
}
2、编程读写一个文件test.txt,每隔1秒向文件中写入一行数据,类似这样:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
该程序应该无限循环,直到按Ctrl+C中断程序,再次启动程序写文件时可以追加到原文件之后,并且序号能够接续上次的序号,比如:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
3, 2007-7-30 15:19:02
4, 2007-7-30 15:19:03
5, 2007-7-30 15:19:04
思路:1.打开文件,a+;2、循环写;3、计算文 件行数;4、time localtime sprintf fprintf
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
FILE *fp = fopen(argv[1],"a+");//定义fp指向a.out后面的文件,权限为可读(第一行开始)可写追加(末尾开始)
if (NULL == fp)
{
printf("fp指向%s文件失败\n",argv[1]);
return -1;
}
else
printf("fp指向%s文件成功\n",argv[1]);
//2、当一行写完进入下一行
int len = 0;//定义行号,从0开始
char buf[32] = {0};//定义fp指向的数组
while(fgets(buf,32,fp))
{
if(buf[strlen(buf)-1] == '\n')//buf的最后一个数不等于换行时
len++;//行数++
}
//3、时间函数
time_t nowtime;//定义时间函数,名为nowtime
//方法一
// while(1)
// {
// time(&nowtime);
// struct tm *p = localtime(&nowtime);
// sprintf(buf,"计数%3d > %4d年%2d月%2d日 %2d:%2d:%2d\n",len,p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
// len++;
// printf("%s",buf);
// fputs(buf,fp);
// sleep(1);
// fflush(NULL);
// }
//
//方法二
while(1)
{
time(&nowtime);
struct tm *p = localtime(&nowtime);
fprintf(fp,"计数%3d > %4d年%2d月%2d日 %2d:%2d:%2d\n",len,p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
fflush(fp);
printf("计数%3d > %4d年%2d月%2d日 %2d:%2d:%2d\n",len,p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
len++;
sleep(1);
}
fclose(fp);
return 0;
}
【文件IO】
[8]int open(const char *pathname, int flags)
功能:打开文件
参数:pathname:文件路径名
flags:打开文件的方式
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
O_CREAT:创建
O_TRUNC:清空
O_APPEND:追加
返回值:成功:文件描述符
失败:-1
当第二个参数中有O_CREAT选项时,需要给open函数传递第三个参数,指定创建文件的权限
int open(const char *pathname, int flags, mode_t mode);
创建出来的文件权限为mode&(~umask) //umask为文件权限掩码|
标准IO |
文件IO |
r |
只读,若文件不存在,报错 O_RDONLY |
r+ |
可读可写,若文件不存在,报错 O_RDWR |
w |
只写,若文件不存在,创建,若存在则清空O_WRONLY|O_CREAT|O_TRUNC |
w+ |
可读可写,若文件不存在,创建,若存在则清空O_RDWR|O_CREAT|O_TRUNC |
a |
追加,只写,不存在创建,存在追加 O_WRONLY|O_CREAT|O_APPEND |
a+ |
追加,可读可写,不存在创建,存在追加 O_RDWR|O_CREAT|O_APPEND |
#include
int main(int argc, char const *argv[])
{
FILE *fp;//创建一个文件指针
fp = fopen("./hello.c","a+");//文件指针指向hello.c文件,并以可读可写追加的形式打开
if(NULL == fp)//容错判断:当fp为空(指向文件失败时)时返回-1
{
perror("fopen error");
return -1;
}
else
printf("fopen success\n");//容错判断:当fp不为空(指向文件成功时)时,提示语句
//while(1);
return 0;
}
[9]int close(int fd)
功能:关闭文件
参数:fd:文件描述符
[10]ssize_t read(int fd, void *buf, size_t count)
功能: 从一个已打开的可读文件中读取数据
参数: fd 文件描述符
buf 存放位置
count 期望的个数
返回值:成功:实际读到的个数
返回-1:表示出错,并设置errno号
返回0: 表示读到文件结尾
[11]ssize_t write(int fd, const void *buf, size_t count)
功能:向指定文件描述符中,写入 count个字节的数据。
参数:fd 文件描述符
buf 要写的内容
count 期望值
返回值:成功:实际写入数据的个数
失败 : -1
[12]off_t lseek(int fd, off_t offset, int whence)
功能:设定文件的偏移位置
参数:fd:文件描述符
offset:偏移量
正数:向文件结尾位置移动
负数:向文件开始位置
whence 相对位置
SEEK_SET 开始位置
SEEK_CUR 当前位置
SEEK_END 结尾位置
返回值:成功:文件的当前位置
失败:-1
练习
1、向文件中第 10 位置处写一个字符,在文件此时的位置,后 20个位置处,写一行字符串hello进去,求此时文件的长度。
2、用文件IO实现cp功能 ./a.out argv[1] argv[2]
[13]pid_t fork(void)
功能:创建子进程
返回值:
成功:在父进程中:返回子进程的进程号 >0
在子进程中:返回值为0
失败:-1并设置errno
特点:
1、子进程几乎拷贝了父进程的全部内容。包括代码、数据、系统数据段中的pc值、栈中的数据、父进程中打开的文件等;但它们的PID、PPID是不同的。
2、父子进程有独立的地址空间,互不影响;当在相应的进程中改变全局变量、静态变量,都互不影响。
3、若父进程先结束,子进程成为孤儿进程,被init进程收养,子进程变成后台进程。
4、若子进程先结束,父进程如果没有及时回收,子进程变成僵尸进程(要避免僵尸进程产生)(killall a.out)
[14]pid_t wait(int *status)
功能: 回收子进程资源(阻塞)
参数: status:子进程退出状态,不接受子进程状态设为NULL
返回值:成功:回收的子进程的进程号
失败:-1
[15]pid_t waitpid(pid_t pid, int *status, int options)
功能: 回收子进程资源
参数:
pid: >0 指定子进程进程号
=-1 任意子进程
=0 等待其组ID等于调用进程的组ID的任一子进程
<-1 等待其组ID等于pid的绝对值的任一子进程
status:子进程退出状态
options:0:阻塞
WNOHANG:非阻塞
返回值:正常:结束的子进程的进程号
当使用选项WNOHANG且没有子进程结束时:0
出错:-1