本文主要是C语言——文件I/O基本操作的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
点击查看相关文件下载
一、文件打开与关闭
1. 基本函数
1.1 open()
在 linux 下可以使用 man 2 open 命令查看该函数的帮助手册。
1 2 3 4 5 6 7 8
| #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
|
【函数说明】该函数打开一个文件,获取文件描述符;打开文件时使用两个参数,创建文件时第三个参数指定新文件的权限。
【函数参数】
- pathname :被打开的文件名(可包括路径名)。
- flags :表示打开文件所采用的操作。
点击查看详细的 flag 常量
(1) flag 常量可取的值
O_RDONLY | 只读方式打开文件。 | 这三个参数互斥 |
O_WRONLY | 可写方式打开文件。 |
O_RDWR | 读写方式打开文件。 |
O_CREAT | 如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限。 |
O_EXCL | 如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。 |
O_NOCTTY | 使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。 |
O_TRUNC | 如文件已经存在,那么打开文件时先删除文件中原有数据。 |
O_APPEND | 以添加方式打开文件,所以对文件的写操作都在文件的末尾进行。 |
【注意】前三个参数必须指定,且只能指定一个,后边的几个可以与前边搭配使用。
(2) flag 常量与标准 I/O 文件打开权限关系、
r | O_RDONLY |
r+ | O_RDWR |
w | O_WRONLY | O_CREAT | O_TRUNC, 0664 |
w+ | O_RDWR | O_CREAT | O_TRUNC, 0664 |
a | O_WRONLY | O_CREAT | O_APPEND, 0664 |
a+ | O_RDWR | O_CREAT | O_APPEND, 0664 |
- mode :表示被打开文件的存取权限,为 8 进制表示法。此参数只有在建立新文件时有效。新建文件时的权限会受到 umask 值影响,实际权限是 mode - umaks
点击查看什么是 umask
在类 unix 系统中, umask 是确定掩码设置的命令,该掩码用来设定文件或目录的初始权限。 umask 确定了文件创建时的初始权限:
1
| 文件或目录的初始权限 = 文件或目录的最大默认权限 - umask权限
|
文件初始默认权限为 0666 ,目录为 0777 ,若用户 umask 为 0002 ,则新创建的文件或目录在没有指定的情况下默认权限分别为 0664 、 0775 )。
在 Linux 下,我们可以使用 umask 命令来查看当前用户默认的 umask 值,同时也可以在 umask 命令后面跟上需要设置的 umask 值来重新设置 umask 。
【返回值】 返回值是一个 int 类型,成功时返回文件描述符(非负整数);出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9
| #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int fd;
fd = open("01open_close.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
【注意事项】 该函数可以打开设备文件,但是不能创建设备文件。
1.2 close()
在 linux 下可以使用 man 2 close 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <unistd.h>
int close(int fd);
|
【函数说明】该函数关闭一个打开的文件。
【函数参数】
【返回值】 返回值是一个整数,成功时返回 0 ;出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6
| #include <unistd.h>
int ret; ret = close(fd);
|
【注意事项】
(1)程序结束时自动关闭所有打开的文件。
(2)文件关闭后,文件描述符不再代表文件。
2. 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int main(int argc,char*argv[]) { int fd; int ret; fd = open("01open_close.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666); if(fd < 0) { printf("open file err\n"); return 0; } else { printf("sucess,fd=%d\n",fd); } ret = close(fd); if(ret < 0) { printf("close failed\n"); }
ret = close(fd); printf("ret=%d\n", ret); return 0; }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
二、文件读写
1. 基本函数
1.1 read()
在 linux 下可以使用 man 2 read 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
|
【函数说明】该函数从文件中读取数据。
【函数参数】
- fd :文件描述符。
- buf :接收数据的缓冲区。
- count :需要读取的字节数,不应超过 buf 。
【返回值】 返回值是 ssize_t 类型(表示有符号的 size_t ),成功时返回实际读取的字节数;出错时返回 EOF ,读到文件末尾时返回 0 。
点击查看 EOF 说明
EOF 是 end of file 的缩写,表示文件末尾,是在 stdio.h 中定义的宏,它的值是一个负数,往往是 -1 ,但是不绝对是 -1 ,也可以是其他负数,这要看编译器的规定。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9
| #include <unistd.h>
int fd; char buff[32]={0}; int ret; fd = open("02read_write.txt",O_RDWR | O_CREAT | O_APPEND, 0666); ret = read(fd, buff, 32);
|
【注意事项】
(1)读取过程中,未读完 count 字节时,若遇到换行,则会一起读取。
(2)对于⼀个数组,总是要自动分配⼀个 ‘\0’ 作为结束,所以实际有效的 buf 长度就成为 sizeof(buf) - 1 了,最好就是在读取完成后自己加上一个 ‘\0’ ,以防止后边打印出现乱码的情况。
1.2 write()
在 linux 下可以使用 man 2 write 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
|
【函数说明】该函数向文件写入数据。
【函数参数】
【返回值】返回值是一个 ssize_t 类型,成功时返回实际写入的字节数;出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6 7 8 9
| #include <unistd.h>
int fd; char buff[32]= "fanhualuojin"; int ret; fd = open("02read_write.txt",O_RDWR | O_CREAT | O_APPEND, 0666); ret = write(fd, buff, strlen(buff));
|
【注意事项】 数据写入完毕后,文件指针指向文件尾部,此时直接读取文件,则什么也读不到,可以使用后边的函数移动指针,再进行读取。
2. 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
#include <string.h>
void test_read(); void test_write();
int main(int argc,char*argv[]) { test_read(); return 0; }
void test_read() { int fd; char buff[32]={0}; int ret; fd = open("02read_write.txt",O_RDWR | O_CREAT | O_APPEND, 0666); if(fd < 0) { printf("open file err\n"); return; } else { printf("sucess,fd=%d\n",fd); } ret = read(fd, buff, 32); if(ret < 0) { perror("read"); close(fd); return; } buff[31] = 0; printf("read buff=%s\n", buff); close(fd); }
void test_write() { int fd; char buff[32]= "fanhualuojin"; char a[32]; int ret; fd = open("02read_write.txt",O_RDWR | O_CREAT | O_APPEND, 0666); if(fd < 0) { printf("open file err\n"); return; } else { printf("sucess,fd=%d\n",fd); } ret = write(fd, buff, strlen(buff)); if(ret < 0) { perror("write"); close(fd); return; } printf("sucess,write count=%d\n",ret); ret = read(fd , a, 32); if(ret < 0) { perror("read"); close(fd); return; } a[31] = 0; printf("read buff=%s\n", a); printf("read count=%d\n",ret); close(fd); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|
三、文件定位
1. lseek()
在 linux 下可以使用 man 2 lseek 命令查看该函数的帮助手册。
1 2 3 4 5
| #include <sys/types.h> #include <unistd.h>
off_t lseek(int fd, off_t offset, intt whence);
|
【函数说明】该函数用于读写文件时偏移文件指针,定位读写位置。
【函数参数】
点击查看 whence 参数
常量 | 描述 |
SEEK_SET | 文件的开头 |
SEEK_CUR | 文件指针的当前位置 |
SEEK_END | 文件的末尾 |
【返回值】返回值是 off_t 类型,成功时返回当前的文件读写位置;出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
1 2 3 4 5 6
| #include <sys/types.h> #include <unistd.h>
lseek(fd, 0, SEEK_SET);
|
【注意事项】lseek()允许将文件偏移量设置在文件末尾之外(但这不会改变文件的大小)。如果稍后在此时写入数据,则后续读取间隙( a “hole”)中的数据将返回空字节(‘\0’),直到读到数据实际写入的位置为止。
2. 使用实例
点击查看实例
test.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
#include <string.h>
void test_none_lseek(); void test_lseek();
int main(int argc,char*argv[]) { test_lseek(); return 0; }
void test_none_lseek() { int fd; char buff[32]= "fanhualuojin"; char a[32]; int ret; fd = open("03lseek.txt",O_RDWR | O_CREAT | O_APPEND, 0666); if(fd < 0) { printf("open file err\n"); return; } else { printf("sucess,fd=%d\n",fd); } ret = write(fd, buff, strlen(buff)); if(ret < 0) { perror("write"); close(fd); return; } printf("sucess,write count=%d\n",ret); ret = read(fd , a, 32); if(ret < 0) { perror("read"); close(fd); return; } a[31] = 0; printf("read buff=%s\n", a); printf("read count=%d\n",ret); close(fd); }
void test_lseek() { int fd; char buff[32]= "fanhualuojin"; char a[33]; int ret; fd = open("03lseek.txt",O_RDWR | O_CREAT | O_APPEND, 0666); if(fd < 0) { printf("open file err\n"); return; } else { printf("sucess,fd=%d\n",fd); } ret = write(fd, buff, strlen(buff)); if(ret < 0) { perror("write"); close(fd); return; } printf("sucess,write count=%d\n",ret); lseek(fd, 0, SEEK_SET); ret = read(fd, a, 33); if(ret < 0) { perror("read"); close(fd); return; } a[sizeof(a)-1] = 0; printf("read buff=%s\n", a); printf("read count=%d\n",ret); close(fd); }
|
在终端执行以下命令编译程序:
1 2
| gcc test.c -Wall # 生成可执行文件 a.out ./a.out # 执行可执行程序
|