湛江网站搜索引擎推广,山东网站建设系统,新网站前期如何做seo,淘宝上做网站怎么样这里写目录标题 华清远见嵌入式2017年线下班#xff1a;文件IO笔记文件权限文件IO文件创建和打开操作文件关闭操作出错处理创建设备文件 || create || 老师自己忘了文件读操作练习#xff1a;计算文件的大小#xff1f;文件写操作练习#xff1a;打开file1和file2#xff… 这里写目录标题 华清远见嵌入式2017年线下班文件IO笔记文件权限文件IO文件创建和打开操作文件关闭操作出错处理创建设备文件 || create || 老师自己忘了文件读操作练习计算文件的大小文件写操作练习打开file1和file2将file1中的内容拷贝到file2,实现文件拷贝功能文件定位操作练习通过lseek计算文件的大小空洞与非空洞文件 (Linux)作业打开file1,file2,file3 ,将file1前一半内容拷贝到file2后一半内容拷贝file3cpp 标准IO文件读操作fopen读写流练习 循环的从标准输入中获取字符如果是数字则显示其他的就不显示练习要求输入字符将大写字母转换成小写小写字母转换成大写。行IO练习获取以个文件的行数。检查文件出错函数直接IO流的格式化输入输出流的定位获取时间文件信息硬链接和软连接获取用户相关信息获取用户分组目录操作函数库静态库特点共享库的特点如何找到共享库 华清远见嵌入式2017年线下班文件IO笔记
文件权限 一第一个字段表示文件类型 和 文件权限。 第1个字母表示文件类型d表示目录类型。其他的linux 文件类型以下七种 二其他6个字母表示分别表示属主权限属组权限其他用户权限。 权限构成 文件权限由三个部分构成分别为
文件所有者 User
同组用户 Group
其他用户 Other每个部分可以用一个数字或三个字母表示
读取的权限等于4用r表示
写入的权限等于2用w表示
执行的权限等于1用x表示数字解释 rwx 属性421 7 rw- 属性42 6 r-x 属性41 7。
以755为例
1-3 位 7等于421rwx所有者具有读取、写入、执行权限
4-6 位 5等于410r-x同组用户具有读取、执行权限但没有写入权限
7-9 位 5等于410r-x其他用户具有读取、执行权限但没有写入权限。444 r–r–r– 600 drw------- 644 drw-r–r– 666 drw-rw-rw- 700 drwx------ 744 drwxr–r– 755 drwxr-xr-x 777 drwxrwxrwx 文件IO
类Linux系统下使用
文件创建和打开操作 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); int creat(const char *pathname, mode_t mode); 函数功能打开、创建文件 函数参数 pathname : 需要打开文件的文件名文件名长度不能超过255。 flags : 打开方式
O_RDONLY只读方式打开文件。
O_WRONLY可写方式打开文件。
O_RDWR读写方式打开文件。
O_CREAT如果该文件不存在就创建一个新的文件并用第三的参数为其设置权限读写执行权限。
O_EXCL如果使用
O_CREAT时文件存在则可返回错误消息。这一参数可测试文件是否存在。
O_TRUNC如文件已经存在那么打开文件时先删除文件中原有数据。
O_APPEND以添加方式打开文件所以对文件的写操作都在文件的末尾进行。//write 文件开始位置开始写文件关闭操作
#include unistd.h
int close(int fildes);
函数参数
fildes : 需要关闭文件的文件描述符
返回值成功 0 失败 -1例1以所有者只写方式参数O_WRONLY打开文件mode64如果文件不存在则创建参数O_CREAT如果文件存在则清空参数O_TRUNC。
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h/*
以所有者只写方式参数O_WRONLY打开文件mode64
如果文件不存在则创建参数O_CREAT
如果文件存在则截短参数O_TRUNC
*/int main(int argc, const char *argv[])
{int fd;// 不指定umask生成的test.txt文件的权限是0664指定了就是0666umask(0); // 在当前目录创建test.txt// 0666 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH// fd open(test.txt, // O_WRONLY | O_CREAT | O_TRUNC , // S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);fd open(test.txt, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,0666);if(-1 fd){perror(open failed);// 后面会自动接perror对应的错误信息}close(fd);//1024return 0;
}
在终端中执行使用命令 ./open
如果存在text.txt文件perror则会报错自动提示错误信息 文件权限还可以使用宏进行表示
出错处理 #include string.h char * strerror(int errnum); 全局错误码errno 是记录系统的最后一次错误代码 #include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h //一定要加这个头文件
/*
以所有者只写方式参数O_WRONLY打开文件mode64
如果文件不存在则创建参数O_CREAT
如果文件存在则截短参数O_TRUNC
*/
int main(int argc, const char *argv[])
{int fd;// 不指定umask生成的test.txt文件的权限是0664指定了就是0666umask(0); // 在当前目录创建test.txtfd open(test.txt, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,0666);if(-1 fd){print(%s\n, strerror(errno));// errno是记录系统的最后一次错误代码}close(fd);//1024return 0;
} 创建设备文件 || create || 老师自己忘了
cat /proc/devices 查看当前系统支持的驱动 主设备号 usb 字符设备 180 设备号 int creat(const char *pathname, mode_t mode); 等价于open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode) #include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
int main(int argc, const char *argv[])
{int fd;fd creat(test.txt, 0666); // open(test.txt, O_WRONLY|O_CREAT|O_TRUNC, 0666);if(-1 fd){perror(creat);}close(fd);//1024return 0;
}文件读操作 #include unistd.h ssize_t read(int fd, void *buf, size_t count); 函数功能从一个已经打开的文件中读取内容函数参数fd : 文件描述符buf : 用来存放读到的内容的缓冲区首地址count 读取的字节数返回值成功 返回实际读取的字节数0 读到文件末尾失败 -1 并设置errno#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[1024] \0; // 可以人为指定不能超过1024字节int count;fd open(test.txt, O_RDONLY | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);if(-1 fd){perror(open failed);}// 每次读取5个字节while((count read(fd, buf, 5)) 0) // 不能 {if(-1 count){perror(read failed);return -1;}printf(count %d : %s\n, count, buf); //count 5}close(fd);//1024return 0;
}练习计算文件的大小
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[1024] \0;int count 0 , sum 0;fd open(test.txt, O_RDONLY | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);if(-1 fd){perror(open failed);}while((count read(fd, buf, 5)) 0){if(-1 count){perror(read failed);return -1;}sum sum count;}printf(The size of file is %d\n, sum);close(fd);//1024return 0;
}文件写操作 #include unistd.h ssize_t write(int fd, const void *buf, size_t count); 函数功能向已经打开的文件中写内容
函数参数fd : 文件描述符buf : 写缓冲缓冲区首地址count : 指定写入的字节数
返回值成功实际写到文件的字节数失败-1#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[1024] \0;char writebuf[1024] xxxxx;int count;// fd open(test.txt, O_RDWR | O_CREAT | O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);// 没有O_APPEND直接覆盖fd open(test.txt, O_RDWR | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if(-1 fd){perror(open failed);}count read(fd, buf, 1);if(-1 count){perror(read failed);return -1;}printf(count %d : %s\n, count, buf);count write(fd, writebuf, strlen(writebuf));if(-1 count){perror(write failed);return -1;}printf(count %d\n, count);// 这里读了一个字符所以偏移了1count read(fd, buf, 1); if(-1 count){perror(read failed);return -1;}printf(count %d : %s\n, count, buf);close(fd);//1024return 0;
}
text.txt里原来的内容是 “abcdefghijk” 输出文件初始read了一个字符位移在第一位往后覆盖 xxxxx
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[1024] \0;char writebuf[1024] xxxxx;int count;// 有O_APPENDfd open(test.txt, O_RDWR | O_CREAT | O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);if(-1 fd){perror(open failed);}count read(fd, buf, 1);if(-1 count){perror(read failed);return -1;}printf(count %d : %s\n, count, buf);count write(fd, writebuf, strlen(writebuf));if(-1 count){perror(write failed);return -1;}printf(count %d\n, count);count read(fd, buf, 1);if(-1 count){perror(read failed);return -1;}printf(count %d : %s\n, count, buf);close(fd);//1024return 0;
}输出在下一行追加 xxxxx
练习打开file1和file2将file1中的内容拷贝到file2,实现文件拷贝功能
diff -s file1 file2 比较两个文件是否一致
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd1, fd2;char buf[1024] \0;int count;if(argc 3){printf(command error source file dest file!\n);return -1;}// 从命令行参数获得文件名fd1 open(argv[1], O_RDONLY);if(-1 fd1){perror(open file1 failed);return -1;}fd2 open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);if(-1 fd2){perror(open file2 failed);return -1;}while((count read(fd1, buf, sizeof(buf))) 0){write(fd2, buf, count);}close(fd1);//1024close(fd2);//1024return 0;
}文件定位操作 #include sys/types.h #include unistd.h off_t lseek(int fd, off_t offset, int whence); 函数功能文件定位
函数参数fd文件描述符offset相对于偏移量偏移量每一读写操作所需要移动的距离单位是字节的数量可正可负向前移向后移whence: 基准点SEEK_SET当前位置为文件的开头新位置为偏移量的大小。
SEEK_CUR当前位置为文件指针的位置新位置为当前位置加上偏移量。
SEEK_END当前位置为文件的结尾新位置为文件的大小加上偏移量的大小。返回值失败 -1成功当前文件的偏移量当前读写位置相对文件开始位置的字节数通过lseek计算文件的大小#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[1024] \0;char writebuf[1024] xxxxx;int count;int offset;fd open(test.txt, O_RDWR | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);if(-1 fd){perror(open failed);}count write(fd, writebuf, strlen(writebuf));if(-1 count){perror(write failed);return -1;}printf(count %d\n, count);//offset lseek(fd, -6, SEEK_CUR);offset lseek(fd, -5, SEEK_CUR);if(-1 offset){perror(lseek);return -1;}count read(fd, buf, 5);if(-1 count){perror(read failed);return -1;}printf(count %d : %s\n, count, buf);close(fd);//1024return 0;
}新建文件写入“xxxxx”然后读取出来。 如果向前偏移量越界时候会直接报错
练习通过lseek计算文件的大小
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[1024] \0;char writebuf[1024] xxxxx;int count;int offset;fd open(test.txt, O_RDWR | O_CREAT , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);if(-1 fd){perror(open failed);}//SEEK_END当前位置为文件的结尾新位置为文件的大小加上偏移量0的大小offset lseek(fd, 0, SEEK_END);if(-1 offset){perror(lseek);return -1;}printf(sizeof file is %d \n, offset);close(fd);//1024return 0;
}空洞与非空洞文件 (Linux)
空洞文件和真实文件的区别在于磁盘的使用情况 du -sh 查看空洞文件和真实文件的区别
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[32] hello, world;int offset;fd open(hole.txt, O_WRONLY | O_CREAT | O_TRUNC, 0644);if(fd 0){printf(%s\n,sterror(errno));return -1;}write(fd, buf, strlen(buf));if((offset lseek(fd, 168898, SEEK_CUR)) 0){perror(lseek);return -1;}write(fd, buf, strlen(buf));close(fd);//1024return 0;
}前后都有hello world.中间全是空洞
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd;char buf[32] hello, world;int offset;fd open(hole.txt, O_WRONLY | O_CREAT | O_TRUNC, 0644);if(fd 0){printf(%s\n,sterror(errno));return -1;}write(fd, buf, strlen(buf));/*if((offset lseek(fd, 168898, SEEK_CUR)) 0){perror(lseek);return -1;}
*/
//真实地往磁盘里写内容for(i 0; i 168898; i){write(fd, x, 1);}write(fd, buf, strlen(buf));close(fd);//1024return 0;
}空洞和非空洞文件都是165K 但是可以通过查看磁盘使用情况区别两个文件的内存大小
作业打开file1,file2,file3 ,将file1前一半内容拷贝到file2后一半内容拷贝file3cpp
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include string.h
#include errno.h
#include unistd.hint main(int argc, const char *argv[])
{int fd1, fd2, fd3, count, nread, size;int buf[1024] \0;if(argc 4){printf(argc 4);return -1;}fd1 open(argv[1], O_RDONLY);if(fd1 0){printf(%s\n,sterror(errno));return -1;}fd2 open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);if(fd2 0){printf(%s\n,sterror(errno));return -1;}fd3 open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0666);if(fd3 0){printf(%s\n,sterror(errno));return -1;}size lseek(fd1, 0, SEEK_END);lseek(fd1, 0, SEEK_SET)while((nread read(fd1, buf, 1)) 0){count;if(count (size/2))write(fd2, buf, nread);else if (count (size/2))write(fd3, buf, nread);} close(fd1);//1024close(fd2);//1024close(fd3);//1024return 0;
}标准IO
只要装了C库就能使用标准IO
open 返回 fd fopen 返回指向FILE结构的指针
1)理解什么是流 输入流入和流出的对象就是流
2)如何描述一个流 内存中开辟一个区域用来存放流的有关信息这些信息是保存在一个结构体类型的变量中该结构体类型是由系统定义的取名为FILE.
3)FILE 指针 fopen 返回指向FILE结构的指针
流的分类 文本流和二进制流 Linux不区分文本和二进制流 windows
#include stdio.hint main(int argc, const char *argv[])
{int i 0;for(i 0;i 379;i) //每次向缓冲区写3个字符{if (i 100)fprintf(stdout,%d,i);else if (i 10)fprintf(stdout,0%d,i);else if (i 0)fprintf(stdout,00%d,i);}while(1);return 0;}
目标是打印000-376 实际上只输出前1024字节 1024/3341.3 个数 即000-340.3因此结尾的4个数是340|3
getchar(); /* why do we need this? 实际使用时才会申请空间*/缓冲缓冲区是通过malloc申请的空间申请的实际是发生I/O操作的时候当程序调用getchar时程序就等着用户按键用户输入的字符被存放在键盘缓冲区中直到用户按回车为止回车字符也放在缓冲区中当用户键入回车之后getchar才开始从stdio流中每次读入一个字符。
getchar函数的返回值是用户输入的字符的ASCII码如出错返回-1且将用户输入的字符回显到屏幕.
总结一下对于磁盘文件通常使用全缓冲区访问。当流涉及一个终端时例如标准输入和标准输出使用行缓冲区标准出错流stderr 通常是不带缓冲区的#include stdio.h
/*1.測試標準輸入和標準輸出採用的是什麼類型的緩衝以及緩衝區的大小*2.普通文件採用的是什麼類型的緩衝以及緩衝區的大小*3.malloc的時間* */
int stream_attribute(FILE *fp)
{if(fp-_flags _IO_UNBUFFERED) {printf(The IO type is unbuffered\n);} else if (fp-_flags _IO_LINE_BUF) {printf(The IO type is line buf\n);} else {printf(The IO type is full buf\n);}printf(The IO buffer size %d (bytes)\n, fp-_IO_buf_end - fp-_IO_buf_base);return 0;
}int main()
{FILE *fp;// 尝试注释掉getchar();观察输出有什么不同getchar(); /* why do we need this? 实际使用时才会申请空间*/printf(stdin ___________________________________\n); stream_attribute(stdin);printf(stdout ___________________________________\n);stream_attribute(stdout);printf(stderr ___________________________________\n);stream_attribute(stderr);printf(normal file ___________________________________\n);//普通文件if ((fp fopen(test.txt,w)) NULL) {perror(fail to fopen);}printf(before write:\n);stream_attribute(fp);fputc(a, fp); //putchar(a) fputc(a, stdout)printf(after write:\n);stream_attribute(fp);return 0;
} 文件读操作fopen #include stdio.h FILE *fopen(const char *path, const char *mode); FILE *fdopen(int fd, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *stream); path : 路径名
mode : 打开方式
r
r
w
w
a
a返回值成功返回 指向FILE的结构体指针流指针失败返回 NULL./hello fileFILE *freopen(const char *path, const char *mode, FILE *stream);作用重定向输入输出流const char *restrict pathname重新定向的文件或者是路径const char *restrict type文件打开的方式restrict fp
被改变的流返回一个新的FILE指针
freopen(file1, w, stdout);读写流
fgetc和getc基本一致除了getc()可能是由宏实现的getchar () getc(stdin) 。 #include stdio.h int getc(FILE *stream); int fgetc(FILE *stream); int getchar(void); 函数参数stream : 流
从指定流中获取一个字符函数返回值成功 返回读到字符的ascII码失败 EOF
到文件末尾getchar()等同于getc(stdin)#include stdio.h int putc(int c, FILE *stream); int fputc(int c, FILE *stream); int putchar(int c); 注意三个函数在使用的时候要一一对应c : 输出的字符acII码stream : 指定的流putchar(c)等价于putc(c,stdout)练习 循环的从标准输入中获取字符如果是数字则显示其他的就不显示
#include unistd.h
#include stdlib.h
#include stdio.hint main(int argc, const char *argv[])
{int c;while(1){c fgetc(stdin);if( ( c 0 ) ( c 9) )fputc(c, stdout);else if(\n c)break;}return 0;
}
练习要求输入字符将大写字母转换成小写小写字母转换成大写。
#include stdio.hint main(int argc, const char *argv[])
{int c;while(1){c fgetc(stdin); //放到了缓冲区if((c a) (c z)){c c - (a - A);fputc(c, stdout);}else if((c A) (c Z)){c c (a - A);fputc(c, stdout);}if(\n c)break;}return 0;
}
行IO char * fgets(char *s, int size, FILE *stream); char *gets(char *s); char* s:用于存储从制定流的缓冲区中获取的数据的首地址
size:缓冲区的长度
stream:指定的流fgets (1) 必须指定缓存的长度n。 此函数一直读到下一个新行符为止但是不超过n-1个字符读入的字符被送入缓存。该缓存以null字符结尾。
(2) 如若该行包括最后一个新行符的字符数超过n-1则只返回一个不完整的行而且缓存总是以null字符结尾。对fgets()的下一次调用会继续读该行。 缓存buf[7] (3) gets()与fgets()的另一个区别是gets()并不将换行符存入缓存中fges会将换行符存到存到缓冲区中
#include stdio.hint main(int argc, const char *argv[])
{char buf[32];gets(buf);
// fgets(buf, sizeof(buf), stdin);printf(%s, buf);return 0;
}注意1char *fgets(char *s ,int size,FILE *stream)的用法
fgets每次至多多size-1个字符每次都把都到的字符存储到s字符串数组内当读到文件末尾EOF或者是换行的时候它会结束。换行符(‘/n’),会被存储到字符数组内部结束时会在字符数组最后一位补一个空位(’/0’)。如果文件中的该行不足bufsize个字符则读完该行就结束。如若该行包括最后一个换行符的字符数超过bufsize-1则fgets只返回一个不完整的行但是缓冲区总是以NULL字符结尾对fgets的下一次调用会继续读该行。如果n大于一行的字符串长度那么当读到字符串末尾的换行符时fgets(..)会返回。并且在s的最后插入字符串结束标志\0。 而s缓冲区剩余的位置不会再填充。注意2char *gets(char *s,FILE *stream)
gets不推荐使用该函数容易造成缓冲区的溢出造成不良的后果。二进制直接I/O。fread()和fwrite()函数支持这种类型的I/O。每次I/O操作读或写某种数量的对象而每个对象具有指定的长度。这两个函数常用于从二进制文件中读或写一个结构。size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);练习获取以个文件的行数。
#include stdio.h
#include string.hint main(int argc, const char *argv[])
{FILE *fp;char buf[1024] \0;int line 0;//step 1: 打开流fp fopen(argv[1], r);if(NULL fp){perror(fopen);return -1;}//step 2: 获取行号while(fgets(buf, sizeof(buf), fp) ! NULL){if(buf[strlen(buf) - 1] \n)line;}printf(The line of %s is %d\n, argv[1], line);return 0;
} int puts(const char *s); 函数功能向标准输出输出一行int fputs(const char *s, FILE *stream); 函数功能向指定的流里输出一行函数fputs()将一个以null符终止的字符串写到指定的流终止符null不写出。 注意这并不一定是每次输出一行因为它并不要求在null符之前一定是新行符。
#include stdio.hint main(int argc, const char *argv[])
{// 中间添加\0char buf[] {a, b, c,\0, d , e, f, \n, \0};fputs(buf, stdout);puts(buf);return 0;
} puts()将一个以null符终止的字符串写到标准输出终止符不写出。但是puts()然后又将一个新行符写到标准输出。
#include stdio.hint main(int argc, const char *argv[])
{// 中间添加\0char buf[] {a, b, c, d , e, f, \n, \0};//fputs(buf, stdout);puts(buf);return 0;
}注意: puts()然后又将一个新行符写到标准输出。fputs不加换行符。
检查文件出错函数 #include stdio.h void clearerr(FILE *stream); int feof(FILE *stream); int ferror(FILE *stream); 函数描述
feof : 用于检测文件末尾标志如果该标志被设置返回非0的值如果没有被设置返回0ferror :用于检测出错标志如果该标志被设置返回非0的值如果没有设置返回0clearerr :用于清除这两个标志用法 while (!feof(fp) !ferror(stdin)) {cTemp fgetc(fp);} 直接IO #include stdio.h size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 函数参数ptr: 缓冲区的首地址stream : 流nmemb :元素个数人为指定的size : 每个元素的大小(人为指定)返回值成功 实际读到元素的个数凑不足一个元素就不算失败 -1size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); 函数参数ptr : 缓冲区首地址size : 元素的daxiaonmemb :元素的个数stream : 流返回值成功 实际写入的元素的个数失败 -1#include stdio.h
#include string.h
#include errno.hint main(int argc, const char *argv[])
{FILE *fp;int data[10];int data1[10];int i;for(i 0; i 10; i){data[i] i;}if((fp fopen(test_file, w)) NULL){fprintf(stderr, fopen failed : %s, strerror(errno));return -1;}fprintf(stdout, [DEBUG] sizeof(int) %d\n, sizeof(int));// fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);// data为缓冲区首地址// fwrite把缓冲区的写入fpif(fwrite(data, sizeof(int), 3, fp) ! 3){perror(fwrite);return -1;}fseek(fp, 0, SEEK_SET);// 换数组data1// fread把fp的写入缓冲区data1if(fread(data1, 3, 2, fp) ! 2){perror(fread);return -1;}// 输出缓冲区for(i 0; i 3; i){printf(%d , data1[i]);}fclose(fp);return 0;
}
凑不够字节的时候
#include stdio.h
#include string.h
#include errno.hint main(int argc, const char *argv[])
{FILE *fp;char buf[20] \0;int nread;if((fp fopen(test_file, r)) NULL){fprintf(stderr, fopen failed : %s, strerror(errno));return -1;}// nread读取2个元素每个元素3个字节所以需要读取6个字节if((nread fread(buf, 3, 2, fp)) -1){perror(fread);return -1;}printf(%s\n, buf);printf(nread %d\n, nread);fclose(fp);return 0;
}
test_file里只有1 2 3 4 \0 5个字节 nread读取2个元素每个元素3个字节所以需要读取6个字节 但是因为test_file只有5个字节所以只能成功读取1个元素nread1,凑不够就不算。 流的格式化输入输出 int printf(const char *format, …); //输出到stdout int fprintf(FILE *stream, const char *format, …); //输出到stream int sprintf(char *str, const char *format, …); // 输出到char *str #include stdio.hint main(int argc, const char *argv[])
{FILE *fp NULL;int a 10;char buf[32] hello world;fp fopen(test, w);if(NULL fp){perror(fopen_2);return -1;}fprintf(fp, %d %s\n,a, buf);printf(%s\n, buf);// 缓冲区被覆盖sprintf(buf, hello farsight %d, a);printf(%s\n, buf);a 11;fprintf(fp, %d %s\n,a, buf); fclose(fp);return 0;
}#include stdio.h int scanf(const char *format, …); //stdin int fscanf(FILE *stream, const char *format, …);//stream #include stdio.hint main(int argc, const char* argv[])
{FILE* fp NULL;int a 10;char buff[32] \0;fp fopen(test, r);if (NULL fp){perror(fopen);return -1;}fscanf(fp,%s%d, buff, a);printf(%s, %d\n, buff, a);fclose(fp);return 0;
} int sscanf(const char *str, const char format, …);//charstr #include stdio.hint main(int argc, const char* argv[])
{FILE* fp NULL;int a, b;char buff[32] \0;char buf[32] 1 2 hello;fp fopen(test, r);if (NULL fp){perror(fopen_2);return -1;}sscanf(buf, %d%d%s, a, b, buff);printf(%s, %d, %d\n, buff, a, b);fclose(fp);return 0;
} 流的定位 int fseek(FILE *stream, long offset, int whence); off_t lseek(int fd, off_t offset, int whence); 参数说明stream : 打开的流offset : 相对于基准点偏移量whence : 基准点返回值 返回值偏移量成功 返回0失败 返回-1返回当前流的偏移量 long ftell(FILE *stream); #include stdio.hint main(int argc, const char *argv[])
{FILE *fp;int ret;long int size;fp fopen(argv[1], r);if(NULL fp){perror(fopen);return -1;}ret fseek(fp, 0, SEEK_END);if(-1 ret){perror(fseek);}size ftell(fp);printf(sizeo file is %ld\n, size);return 0;
}
void rewind(FILE *stream);
rewind() 等价于 (void)fseek(stream, 0L, SEEK_SET)实验三
打开文件方式a接上一次的行号计算行号
获取时间 time #include time.h time_t time(time_t *t); time_t long 函数功能返回从1970-1-1 0:0:0到函数调用那一刻的秒数如果t非NULL就将时间填入到t所指向的内存空间返回值成功 时间失败 ((time_t) -1) #include time.h struct tm *localtime(const time_t *timep); 函数功能将秒数转换成具体的时间函数参数timep : 存秒数的地址返回值#include stdio.h
#include time.hint main(int argc, const char *argv[])
{time_t mytime;struct tm *p;mytime time(NULL);p localtime(mytime);printf(%d-%d-%d %d:%d:%d\n, p-tm_year1900, p-tm_mon1, p-tm_mday, p-tm_hour, p-tm_min, p-tm_sec);return 0;
}文件信息
获取文件属性 #include unistd.h #include sys/types.h #include sys/stat.h int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf); 函数参数
struct stat {dev_t st_dev; /* ID of device containing file */ino_t st_ino; /* inode number */mode_t st_mode; /* protection */nlink_t st_nlink; /* number of hard links */uid_t st_uid; /* user ID of owner */gid_t st_gid; /* group ID of owner */dev_t st_rdev; /* device ID (if special file) */off_t st_size; /* total size, in bytes */blksize_t st_blksize; /* blocksize for file system I/O */blkcnt_t st_blocks; /* number of 512B blocks allocated */time_t st_atime; /* time of last access */time_t st_mtime; /* time of last modification */time_t st_ctime; /* time of last status change */ };三个函数的返回若成功则为0若出错则为-1,并且设置errno.给定一个pathname的情况下stat函数返回一个与此命名文件有关的信息结构fstat函数获得已在描述符filedes上打开的文件的有关信息lstat函数类似于stat但是当命名的文件是一个符号连接时lstat返回该符号连接的有关信息而不是由该符号连接引用的文件的信息stat与之相反返回的是链接文件引用的文件的信息#include stdio.h
#include sys/types.h
#include sys/stat.h
#include unistd.hint main(int argc, const char *argv[])
{struct stat buf;stat(argv[1], buf); printf(size of %s is %d\n, argv[1], buf.st_size);return 0;
}
st_mode
首先S_IFMT是一个掩码它的值是017000注意这里用的是八进制 可以用来过滤出前四位表示的文件类型。其后的连续七个分别对应套接口文件、符号链接文件、普通文件、块设备、目录、字符设备、管道它们分别对应一个不同的值。#include stdio.h
#include sys/types.h
#include sys/stat.h
#include unistd.hint main(int argc, const char *argv[])
{struct stat buf;lstat(argv[1], buf);
#if 0if(S_ISREG(buf.st_mode))printf(regular file\n);else if(S_ISDIR(buf.st_mode))printf(directory\n);else if(S_ISCHR(buf.st_mode))printf(character device\n);else if(S_ISBLK(buf.st_mode))printf(block device\n);else if(S_ISFIFO(buf.st_mode))printf(FIFO\n);else if(S_ISLNK(buf.st_mode))printf(symbolic link\n);else if(S_ISSOCK(buf.st_mode))printf(socket\n);
#elseswitch(S_IFMT buf.st_mode){case S_IFSOCK:printf(socket\n);break;case S_IFLNK:printf(symbolic link\n);break;case S_IFREG:printf(regular file\n);break;case S_IFBLK:printf(block device\n);break;case S_IFDIR:printf(directory\n);break;case S_IFCHR:printf(character device\n);break;case S_IFIFO:printf(FIFO\n);break;default:printf(error\n);}#endifreturn 0;
}硬链接和软连接
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include unistd.hint main(int argc, const char *argv[])
{struct stat buf;stat(argv[1], buf); printf(number of hand link is %d\n, buf.st_nlink);return 0;
}获取用户相关信息 #include sys/types.h #include pwd.h struct passwd *getpwuid(uid_t uid); uid : 用户ID struct passwd {char *pw_name; /* username */char *pw_passwd; /* user password */uid_t pw_uid; /* user ID */gid_t pw_gid; /* group ID */char *pw_gecos; /* user information */char *pw_dir; /* home directory */char *pw_shell; /* shell program */
};#include stdio.h
#include sys/types.h
#include sys/stat.h
#include unistd.h
#include pwd.hint main(int argc, const char *argv[])
{struct stat buf;struct passwd *p;stat(argv[1], buf); p getpwuid(buf.st_uid);printf(file owner is %s\n, p-pw_name);return 0;
}获取用户分组 #include sys/types.h #include grp.h struct group *getgrgid(gid_t gid); gid :用户组ID struct group {char *gr_name; /* group name */char *gr_passwd; /* group password */gid_t gr_gid; /* group ID */char **gr_mem; /* group members */
};#include stdio.h
#include sys/types.h
#include sys/stat.h
#include unistd.h
#include pwd.h
#include grp.hint main(int argc, const char *argv[])
{struct stat buf;struct group *p;stat(argv[1], buf); p getgrgid(buf.st_gid);printf(file group is %s\n, p-gr_name);return 0;
}目录操作函数
#include stdio.h
#include sys/types.h
#include dirent.hint main(int argc, const char *argv[])
{DIR *dir;struct dirent *p;//step 1:打开目录dir opendir(argv[1]); if(NULL dir){perror(opendir);return -1;}//step 2:读目录while((p readdir(dir)) ! NULL){if(!strncmp(., p-d_name, 1))continue;printf(%s\t, p-d_name);}printf(\n);//step 3:关闭目录closedir(dir);return 0;
}
库
Linux的库文件保存在 /lib /usr/lib文件夹下 Linux和window下库文件的格式不兼容。
静态库特点
编译(链接)时把静态库中相关代码复制到可执行文件中直接加载静态库中对应的代码 不是全部是部分。
程序中已包含代码运行时不再需要静态库。
静态库升级后程序需要重新编译链接。
编写库源码hello.c
#include stdio.h
void hello(void) {printf(“hello world\n”);return;
}编译生成目标文件 gcc -c hello.c -Wall 创建静态库 hello ar crs libhello.a hello.o 静态库名称libhello.a 名称都是有规范的libXXXX.a 根据后面的执行文件hello.o生成静态库 查看库中符号信息 nm libhello.a 链接静态库
编写应用程序test.c
#include stdio.h
void hello(void);int main() {hello();
return 0;
}编译test.c 并链接静态库libhello.a gcc -o test test.c -L. -lhello 因为静态库里的代码已经加载到了程序里所以删除静态库不影响程序执行
共享库的特点
编译(链接)时仅记录用到哪个共享库中的哪个符号不复制共享库中相关代码。
程序不包含库中代码尺寸小。
程序运行时需要加载库。
库升级方便无需重新编译程序。
编写库源码hello.c bye.c
#include stdio.hvoid hello(void) {printf(“hello world\n”);return;
}#include stdio.hvoid hello(void) {printf(“Bye\n”);return;
}编译生成目标文件 gcc -c -fPIC hello.c bye.c -Wall 使用相对寻址可以加载到不同位置
创建共享库 common gcc -shared -o libcommon.so.1 hello.o bye.o libcommon.so.1libcommon.so.X的X代表库的版本libcommon.so.2libcommon.so.3… 为共享库文件创建链接文件 ln -s libcommon.so.1 libcommon.so 符号链接文件命名规则 lib库名.so 链接共享库 编写应用程序test.c #include stdio.h
#include “common.h”int main() {hello();bye();return 0;
}编译test.c 并链接共享库libcommon.so gcc -o test test.c -L. -lcommon gcc首先链接共享库再链接静态库 gcc -o test test.c -L. -lcommon -static 指定链接静态库 执行程序 ./test
./test: error while loading shared libraries: libcommon.so cannot open shared object file : No such file or directory 当前目录不在系统搜索路径里所以会报错。
添加共享库的加载路径 export LD_LIBRARY_PATH$LD_LIBRARY_PATH:. LD_LIBRARY_PATH可以添加环境中缺省的路径 如何找到共享库 把库拷贝到/usr/lib和/lib目录下 不推荐会跟系统库混乱 在LD_LIBRARY_PATH环境变量中添加库所在路径 临时的只对当前shell起作用 添加/etc/ld.so.conf.d/XXX.conf文件执行ldconfig刷新