函数的参数和返回值使用方法:
参数:
如果参数是指针,通常都是地址传参
如果参数是一个一级指针,定义一个普通变量取地址,
如果是一个二级指针,定义一个一级指针取地址,以此类推
注意:字符串除外
返回值:
返回值是什么类型,就定义什么类型的变量接收
fopen()/fclose()
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
功能:
打开或者创建一个文件
参数:
pathname:
要打开或者创建的文件名,可以跟路径,如果不跟路径,默认就是当前路径
mode:
操作权限
r 以只读的方式打开,如果文件不存在则报错,文件指针定位到文件的起始位置
r+ 以读写的方式打开,如果文件不存在则报错,文件指针定位到文件的起始位置
w 以只写的方式打开,如果文件存在则清空,文件不存在则创建,文件指针定位到文件的起始位置
w+ 以读写的方式打开,如果文件存在则清空,文件不存在则创建,文件指针定位到文件的起始位置
a 以只写的方式打开,如果文件存在则追加,文件不存在则创建,文件指针定位到文件的起末尾位置
a+ 以读写的方式打开,如果文件存在则追加,文件不存在则创建,文件指针定位到文件的起末尾位置
返回值:
成功:
文件指针
失败:
NULL
#include <stdio.h>
int fclose(FILE *stream);
功能:
关闭一个文件指针,如果关闭了文件指针,就无法再通过这个文件指针对文件进行操作了
参数:
stream:
文件指针,fopen的返回值
返回值:
成功:
0
失败:
EOF
perror()/errno
#include <stdio.h>
void perror(const char *s);
功能:
输出一个函数调用失败之后的错误信息
参数:
s:
提示语句
返回值:
无
#include <errno.h>
int errno;
errno是一个全局变量,用于输出函数调用失败的错误码,
可以调用strerror函数通过errno值打印错误信息
#include <stdio.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
//使用fopen函数打开或者创建一个文件
FILE *fp;
//r:只读,如果文件不存在则报错
//fp = fopen("file.txt", "r");
//w:只写,如果文件不存在则创建,如果存在则清空
//fp = fopen("file.txt", "w");
//只写:如果文件不存在则创建,如果文件存在则追加
fp = fopen("file.txt", "a");
if(fp == NULL)
{
//errno是一个保存在errno.h中的全局变量,用于获取函数调用失败的错误码
printf("errno = %d\n", errno);
//使用perror函数打印函数调用失败的错误信息
perror("fopen error");
return -1;
}
//关闭文件指针
fclose(fp);
return 0;
}
3.fgetc()/fputc()
3.1 fgetc()
#include <stdio.h>
int fgetc(FILE *stream);
功能:
从文件中读取一个字符
参数:
stream:
文件指针
返回值:
成功:
读取的字节
失败:
EOF
如果文件内容读取完毕,也会返回EOF
#include <stdio.h>
int main(int argc, char const *argv[])
{
//从终端读取一个字符
#if 0
int a = fgetc(stdin);
printf("a = %c %d\n", a, a);
#endif
//从文件中读取一个字符
FILE *fp;
fp = fopen(argv[1], "r");
if(fp == NULL)
{
perror("fopen error");
return -1;
}
int a;
#if 0
if((a = fgetc(fp)) == EOF)
{
perror("fgetc error");
return -1;
}
printf("a = %c %d\n", a, a);
if((a = fgetc(fp)) == EOF)
{
perror("fgetc error");
return -1;
}
printf("a = %c %d\n", a, a);
#endif
//文件中每一行的结尾都有一个结束标志换行符,fgetc可以读取到整个换行符
while((a = fgetc(fp)) != EOF)
{
printf("a = %c %d\n", a, a);
}
fclose(fp);
return 0;
}
3.2 练习:编写函数,获取文件的行数
#include <stdio.h>
int GetLine(const char *filename)
{
FILE *fp;
if((fp = fopen(filename, "r")) == NULL)
{
perror("fopen error");
return -1;
}
//通过fgetc函数读取文件内容,比较行结束符的个数
int ch, num = 0;
while((ch = fgetc(fp)) != EOF)
{
if(ch == '\n')
{
num++;
}
}
return num;
}
int main(int argc, char const *argv[])
{
int len;
len = GetLine(argv[1]);
if(len >= 0)
{
printf("%s文件一共有%d行\n", argv[1], len);
}
return 0;
}
3.3 fputc()
#include <stdio.h>
int fputc(int c, FILE *stream);
功能:
向指定的文件中写入一个字符
参数:
c:
要写入的字符
stream:
文件指针
返回值:
成功:
写入的字符
失败:
EOF
#include <stdio.h>
int main(int argc, char const *argv[])
{
//向终端写入一个字符
#if 0
fputc('w', stdout);
fputc(10, stdout);
int ch = 97;
fputc(ch, stdout);
fputc(10, stdout);
#endif
//向文件写入一个字符
FILE *fp;
if((fp = fopen(argv[1], "w+")) == NULL)
{
perror("fopen error");
return -1;
}
if(fputc('w', fp) == EOF)
{
perror("fputc error");
return -1;
}
if(fputc('w', fp) == EOF)
{
perror("fputc error");
return -1;
}
if(fputc('h', fp) == EOF)
{
perror("fputc error");
return -1;
}
if(fputc('o', fp) == EOF)
{
perror("fputc error");
return -1;
}
//如果先往文件中写数据,然后读数据,读的位置是最后写
//完数据的下一个位置,因为写和读的文件指针定位的位置
//是同一个
#if 0
int ch;
while((ch = fgetc(fp)) != EOF)
{
printf("ch = %c %d\n", ch, ch);
}
#endif
fclose(fp);
return 0;
}
3.4 练习:实现cp功能
#include <stdio.h>
//使用fgetc和fputc函数实现命令cp的功能
int main(int argc, char const *argv[])
{
//cp命令的功能为读取一个文件的内容写入另一个文件
//打开或者创建这两个文件
FILE *fp_r, *fp_w;
if((fp_r = fopen(argv[1], "r")) == NULL)
{
perror("fopen error");
return -1;
}
if((fp_w = fopen(argv[2], "w")) == NULL)
{
perror("fopen error");
return -1;
}
//读取argv[1]文件的内容写入argv[2]文件
int ch;
while((ch = fgetc(fp_r)) != EOF)
{
fputc(ch, fp_w);
}
printf("cp done\n");
fclose(fp_r);
fclose(fp_w);
return 0;
}
4.fgets()/fputs()
4.1 fgets()
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
功能:
从文件中读取一个字符串
参数:
s:
保存读取的内容
size:
要读取的字节数
stream:
文件指针
返回值:
成功:
返回读取的内容
失败:
NULL
如果读到文件末尾,也返回NULL
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
//从终端读取一个字符串
#if 0
//如果输入的数据的字节数小于第二个参数,会将回车符也当做是字符保存在第一个参数里面
//如果输入的数据的字节数大于第二个参数n,则只会保存n-1个字节,最后一个位置补\0
//注意需要保证第一个参数足够大,否则会内存越界
char str[32] = {0};
fgets(str, 32, stdin);
//如果输入的字节数小于第二个参数,会多出一个换行符,所以我们需要处理整个垃圾字符
//处理的方法是将\n替换成\0
str[strlen(str) - 1] = '\0';
printf("str = %s\n", str);
#endif
//从文件中读取一个字符串
FILE *fp;
if((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen error");
return -1;
}
//如果设置的第二个参数n的值小于一行内容,则只会读取n-1个字节,最后一个位置补\0
//当fgets读取文件内容时,不管什么时候,只要读取的时候遇到行结束符,
//就会立即结束本次的读取
char buf[32] = {0};
fgets(buf, 8, fp);
printf("buf = [%s]\n", buf);
char buf1[32] = {0};
fgets(buf1, 8, fp);
printf("buf1 = [%s]\n", buf1);
return 0;
}
4.2 练习:使用fgets获取文件的行数
#include <stdio.h>
#include <string.h>
int GetLine(const char *filename)
{
FILE *fp;
if((fp = fopen(filename, "r")) == NULL)
{
perror("fopen error");
return -1;
}
char buf[32] = {0};
int num = 0;
while(fgets(buf, 32, fp) != NULL)
{
//hello world\n\0]
if(buf[strlen(buf) - 1] == '\n')
{
num++;
}
}
return num;
}
int main(int argc, char const *argv[])
{
int len = GetLine(argv[1]);
if(len >= 0)
{
printf("%s文件一共有%d行\n", argv[1], len);
}
return 0;
}
4.3 fputs()
#include <stdio.h>
int fputs(const char *s, FILE *stream);
功能:
向文件写入一个字符串
参数:
s:
要写入的字符串
stream:
文件指针
返回值:
成功:
1
失败:
EOF
#include <stdio.h>
int main(int argc, char const *argv[])
{
//向终端写入一个字符串
#if 0
int n = fputs("hello world\n", stdout);
printf("n = %d\n", n);
n = fputs("nihao bei\0jing", stdout);
printf("n = %d\n", n);
#endif
//向文件写入数据
FILE *fp;
if((fp = fopen(argv[1], "w")) == NULL)
{
perror("fopen error");
return -1;
}
int n = fputs("hello world\n", fp);
printf("n = %d\n", n);
return 0;
}
5.fprintf()/sprintf()
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char name[32] = "zhangsan";
FILE *fp;
if((fp = fopen(argv[1], "w")) == NULL)
{
perror("fopen error");
return -1;
}
// char buf[32] = "My name is ";
// strcat(buf, name);
// fputs(buf, fp);
//将按照格式输出的字符串写入文件
fprintf(fp, "My name is %s\n", name);
char buf1[32] = {0};
//将按照格式输出的字符串写入数组中
sprintf(buf1, "My name is %s", name);
printf("buf1 = %s\n", buf1);
return 0;
}
作业:
在家目录下创建一个文件test.txt,每过一秒向文件里面写入一行内容,例如:
001. 2018-06-22 15:16:30
002. 2018-06-22 15:16:31
003. 2018-06-22 15:16:32
004. 2018-06-22 15:16:33
005. 2018-06-22 15:16:34
程序退出之后,下一次运行时接着之前的内容继续写,并且编号是连续的
006. 2018-06-22 15:17:23
007. 2018-06-22 15:17:24
提示:
使用time函数可以获取从1970年1月1日00:00:00到当前的所有的秒数
使用localtime将其转化为日期
#include <time.h>
time_t time(time_t *tloc);
功能:获取从1970年1月1日0时0分0秒到当前的所有秒数
参数:
tloc:获取的秒数
返回值:
成功:获取的秒数
失败:-1
#include <time.h>
struct tm *localtime(const time_t *timep);
功能:将time函数获取的秒数转化为当前的日期和时间
参数:
timep:通过time函数获取的秒数
返回值:
成功:转化后的日期和时间
struct tm {
int tm_sec; /* 秒 (0-60) */
int tm_min; /* 分 (0-59) */
int tm_hour; /* 小时 (0-23) */
int tm_mday; /* 日 (1-31) */
int tm_mon; /* 月 (0-11) */
int tm_year; /* 年 (-1900) */
int tm_wday; /* 星期 (0-6, Sunday = 0) */
int tm_yday; /* 一年的第几天 (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
失败:NULL
#include <stdio.h>
#include <time.h>
int main(int argc, char const *argv[])
{
//以后如果见到_t类型的数据类型,称之为类整形,
//一般都是整数类型取别名得到的
time_t mytime;
time(&mytime);
printf("mytime = %ld\n", mytime);
//通过localtime函数获取日期和时间
struct tm *mytm = localtime(&mytime);
printf("%04d/%02d/%02d %02d:%02d:%02d\n", mytm->tm_year+1900, mytm->tm_mon+1, mytm->tm_mday,mytm->tm_hour, mytm->tm_min, mytm->tm_sec);
return 0;
}
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#define FILENAME "/home/stu/test.txt"
int main(int argc, char const *argv[])
{
//现在家目录下创建一个文件test.txt
FILE *fp;
if((fp = fopen(FILENAME, "a+")) == NULL)
{
perror("fopen error");
return -1;
}
//获取当前文件的行数
int ch;
int len = 0;
while((ch = fgetc(fp)) != EOF)
{
if(ch == '\n')
{
len++;
}
}
//循环将数据写入文件
time_t mytime;
struct tm *mytm;
while(1)
{
len++;
time(&mytime);
mytm = localtime(&mytime);
printf("%03d. %04d/%02d/%02d %02d:%02d:%02d\n",len, mytm->tm_year+1900, mytm->tm_mon+1, mytm->tm_mday,mytm->tm_hour, mytm->tm_min, mytm->tm_sec);
fprintf(fp, "%03d. %04d/%02d/%02d %02d:%02d:%02d\n",len, mytm->tm_year+1900, mytm->tm_mon+1, mytm->tm_mday,mytm->tm_hour, mytm->tm_min, mytm->tm_sec);
fflush(fp);
//因为对文件操作是全缓冲,全缓冲刷新缓冲区的方法:1、程序正常结束 2、使用fflush函数 3、缓冲区满,因为要对文件进行实时写入,所以要调用fflush()进行刷新
sleep(1);
}
return 0;
}
6.获取行缓冲和全缓冲大小
#include <stdio.h>
int main(int argc, char const *argv[])
{
//stdout
printf("hello world\n");
printf("行缓冲大小:%ld字节\n", stdout->_IO_buf_end - stdout->_IO_buf_base);
FILE *fp = fopen("file.txt", "w");
fputc('w', fp);
printf("全缓冲大小:%ld字节\n", fp->_IO_buf_end - fp->_IO_buf_base);
return 0;
}
7.fread()/fwrite()
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
从文件中读取任意类型的内容
参数:
ptr:
保存的数据
size:
每一个块(对象)的长度
nememb:
块数(对象数)
stream:
文件指针
返回值:
成功:
实际读取的块数(对象数)
失败:
0
读取到文件末尾也返回0
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:
向文件写入任意类型的内容
参数:
ptr:
要写入的数据
size:
每一个块(对象)的长度
nememb:
块数(对象数)
stream:
文件指针
返回值:
成功:
写入的块数(对象数),从第一个参数的首地址数据开始一直写指定的字节数
失败:
0
fwrite.c
#include <stdio.h>
int main(int argc, char const *argv[])
{
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return -1;
}
FILE *fp;
if((fp = fopen(argv[1], "w")) == NULL)
{
perror("fopen error");
return -1;
}
//使用fwrite函数向文件写入内容
//string
// size_t n = fwrite("hello world", 2, 5, fp);
// printf("n = %lu\n", n);
//array
// int a[6] = {100, 200, 300, 400, 500, 600};
// size_t n = fwrite(a, 4, 6, fp);
// printf("n = %lu\n", n);
//struct
typedef struct{
int a;
char b;
char c[32];
}MSG;
MSG msg = {100, 'w', "hello world"};
size_t n = fwrite(&msg, sizeof(msg), 1, fp);
printf("n = %lu\n", n);
return 0;
}
fread.c
#include <stdio.h>
int main(int argc, char const *argv[])
{
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return -1;
}
FILE *fp;
if((fp = fopen(argv[1], "r")) == NULL)
{
perror("fopen error");
return -1;
}
//使用fread函数读取文件内容
//string
// char buf[32] = {0};
// size_t n = fread(buf, 2, 100, fp);
// printf("n = %lu, buf = %s\n", n, buf);
//array
// int a[6];
// size_t n = fread(a, 4, 5, fp);
// printf("n = %lu, a[0] = %d, a[1] = %d, a[2] = %d\n", n, a[0], a[1], a[2]);
//struct
typedef struct{
int a;
char b;
char c[32];
}MSG;
MSG msg;
size_t n = fread(&msg, sizeof(msg), 1, fp);
printf("n = %lu, a = %d, b = %c, c = %s\n", n, msg.a, msg.b, msg.c);
return 0;
}
8.fseek()/rewind()/ftell()
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
功能:
定位文件指针的位置
参数:
stream:
文件指针
offset:
要偏移的位置,可正可负
whence:
相对位置
SEEK_SET
文件起始位置,为0
SEEK_CUR
文件当前位置
SEEK_END
文件末尾位置,最后一个字符的下一个位置
返回值:
成功:
0
失败:
-1
void rewind(FILE *stream);
功能:
将文件指针定位到起始位置
参数:
stream:
文件指针
返回值:
无
rewind(fp) <==> fseek(fp, 0, SEEK_SET);
long ftell(FILE *stream);
功能:
获取当前文件指针定位的位置
参数:
stream:
文件指针
返回值:
成功:
当前文件指针定位的位置
失败:
-1
#include <stdio.h>
int main(int argc, char const *argv[])
{
if(argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return -1;
}
FILE *fp;
//如果fopen执行是权限设置为a或者a+,写操作的文件指针的位置
//永远无法改变,只能在文件末尾,但是读操作没有影响
if((fp = fopen(argv[1], "a+")) == NULL)
{
perror("fopen error");
return -1;
}
//获取当前文件指针的位置
printf("offset = %ld\n", ftell(fp));
fputs("0123456789", fp);
//获取当前文件指针的位置
printf("offset = %ld\n", ftell(fp));
//将文件指针的位置定位到起始位置
// rewind(fp);
//fseek(fp, 0, SEEK_SET);
//通过fseek定位文件指针的位置
//定位到第四个位置
// fseek(fp, 4, SEEK_SET);
//定位到文件倒数第四个位置
fseek(fp, -4, SEEK_END);
printf("offset = %ld\n", ftell(fp));
fputs("abcdefg", fp);
rewind(fp);
char buf[64] = {0};
fgets(buf, 32, fp);
printf("buf = [%s]\n", buf);
return 0;
}