LV030-文件IO简介
本文主要是C语言——文件I/O基本操作的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
一、文件打开与关闭
1. open()
在 linux 下可以使用 man 2 open 命令查看该函数的帮助手册。
/* 需包含的头文件 */
#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 :表示打开文件所采用的操作。
(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
Tips:什么是 umask?在类 unix 系统中, umask 是确定掩码设置的命令,该掩码用来设定文件或目录的初始权限。 umask 确定了文件创建时的初始权限:
c文件或目录的初始权限 = 文件或目录的最大默认权限 - umask权限文件初始默认权限为 0666 ,目录为 0777 ,若用户 umask 为 0002 ,则新创建的文件或目录在没有指定的情况下默认权限分别为 0664 、 0775 )。
在 Linux 下,我们可以使用 umask 命令来查看当前用户默认的 umask 值,同时也可以在 umask 命令后面跟上需要设置的 umask 值来重新设置 umask 。
【返回值】 返回值是一个 int 类型,成功时返回文件描述符(非负整数);出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
/* 需要包含的头文件 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* 至少应该有的语句 */
int fd;/* 接收文件描述符 */
/* 以只写方式打开文件01open_close.txt。如果文件不存在则创建,如果文件存在则清空 */
fd = open("01open_close.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);【注意事项】 该函数可以打开设备文件,但是不能创建设备文件。
2. close()
在 linux 下可以使用 man 2 close 命令查看该函数的帮助手册。
/* 需包含的头文件 */
#include <unistd.h>
/* 函数声明 */
int close(int fd);【函数说明】该函数关闭一个打开的文件。
【函数参数】
- fd :已打开文件的文件描述符。
【返回值】 返回值是一个整数,成功时返回 0 ;出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
/* 需要包含的头文件 */
#include <unistd.h>
/* 至少应该有的语句 */
int ret;/* 保存文件关闭返回值 */
ret = close(fd);【注意事项】
(1)程序结束时自动关闭所有打开的文件。
(2)文件关闭后,文件描述符不再代表文件。
2. 使用实例
/* 头文件 */
#include <stdio.h>
/* read write close函数 */
#include <unistd.h>
/* open 函数 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc,char*argv[])
{
int fd;/* 接收文件描述符 */
int ret;/* 保存文件关闭返回值 */
/* 1. 打开文件 man 2 open*/
fd = open("01open_close.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
/* 2. 判断是否打开成功 */
if(fd < 0)
{
printf("open file err\n");
return 0;
}
else
{
printf("sucess,fd=%d\n",fd);
}
/* 3. 关闭文件 */
ret = close(fd);
if(ret < 0)
{
printf("close failed\n");
}
ret = close(fd);
printf("ret=%d\n", ret);
return 0;
}在终端执行以下命令编译程序:
gcc test.c -Wall # 生成可执行文件 a.out
./a.out # 执行可执行程序二、文件读写
1. 基本函数
1.1 read()
在 linux 下可以使用 man 2 read 命令查看该函数的帮助手册。
/* 需包含的头文件 */
#include <unistd.h>
/* 函数声明 */
ssize_t read(int fd, void *buf, size_t count);【函数说明】该函数从文件中读取数据。
【函数参数】
- fd :文件描述符。
- buf :接收数据的缓冲区。
- count :需要读取的字节数,不应超过 buf 。
【返回值】 返回值是 ssize_t 类型(表示有符号的 size_t ),成功时返回实际读取的字节数;出错时返回 EOF ,读到文件末尾时返回 0 。EOF 是 end of file 的缩写,表示文件末尾,是在 stdio.h 中定义的宏,它的值是一个负数,往往是 -1 ,但是不绝对是 -1 ,也可以是其他负数,这要看编译器的规定。
【使用格式】一般情况下基本使用格式如下:
/* 需要包含的头文件 */
#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 命令查看该函数的帮助手册。
/* 需包含的头文件 */
#include <unistd.h>
/* 函数声明 */
ssize_t write(int fd, const void *buf, size_t count);【函数说明】该函数向文件写入数据。
【函数参数】
fd :文件描述符。
buf :要写入文件的数据的缓冲区。
count :需要写入的字节数,不应超过 buf 。
【返回值】返回值是一个 ssize_t 类型,成功时返回实际写入的字节数;出错时返回 EOF 。
【使用格式】一般情况下基本使用格式如下:
/* 需要包含的头文件 */
#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. 使用实例
/* 头文件 */
#include <stdio.h>
/* read write close函数 */
#include <unistd.h>
/* open 函数 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* strlen 函数 */
#include <string.h>
void test_read();
void test_write();
int main(int argc,char*argv[])
{
test_read();
// test_write();
return 0;
}
/**
* @Function: ssize_t read(int fd, void *buf, size_t count);
* @Description: 成功时返回实际读取的字节数;出错时返回EOF
*/
void test_read()
{
/* 定义一个文件描述符变量 */
int fd;
char buff[32]={0};
int ret;
/* 1. 打开当前路径下文件 */
fd = open("02read_write.txt",O_RDWR | O_CREAT | O_APPEND, 0666);
/* 2. 判断是否打开成功 */
if(fd < 0)
{
printf("open file err\n");
return;
}
else
{
printf("sucess,fd=%d\n",fd);
}
/* 3. 读取文件内容 */
ret = read(fd, buff, 32);
if(ret < 0)
{
perror("read");
close(fd);
return;
}
buff[31] = 0;
printf("read buff=%s\n", buff);
/* 4. 关闭文件 */
close(fd);
}
/**
* @Function: ssize_t write(int fd, void *buf, size_t count);
* @Description: 成功时返回实际写入的字节数;出错时返回EOF
*/
void test_write()
{
/* 定义一个文件描述符变量 */
int fd;
char buff[32]= "fanhualuojin";
char a[32];
int ret;
/* 1. 打开当前路径下文件 */
fd = open("02read_write.txt",O_RDWR | O_CREAT | O_APPEND, 0666);
/* 2. 判断是否打开成功 */
if(fd < 0)
{
printf("open file err\n");
return;
}
else
{
printf("sucess,fd=%d\n",fd);
}
/* 3. 写入文件内容 */
ret = write(fd, buff, strlen(buff));
if(ret < 0)
{
perror("write");
close(fd);
return;
}
printf("sucess,write count=%d\n",ret);
/* 4. 读取文件内容,这里会发现什么也读不到,可以看下一个例子,这里还仅仅是测试写入函数 */
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);
/* 5. 关闭文件 */
close(fd);
}在终端执行以下命令编译程序:
gcc test.c -Wall # 生成可执行文件 a.out
./a.out # 执行可执行程序三、文件定位
1. lseek()
在 linux 下可以使用 man 2 lseek 命令查看该函数的帮助手册。
/* 需包含的头文件 */
#include <sys/types.h>
#include <unistd.h>
/* 函数声明 */
off_t lseek(int fd, off_t offset, intt whence);【函数说明】该函数用于读写文件时偏移文件指针,定位读写位置。
【函数参数】
fd :文件描述符。
offset :相对于 whence (基准)的偏移量。
whence :添加偏移 offset 的位置。 whence 参数取值如下:
| 常量 | 描述 |
| SEEK_SET | 文件的开头 |
| SEEK_CUR | 文件指针的当前位置 |
| SEEK_END | 文件的末尾 |
【使用格式】一般情况下基本使用格式如下:
/* 需要包含的头文件 */
#include <sys/types.h>
#include <unistd.h>
/* 至少应该有的语句 */
lseek(fd, 0, SEEK_SET);【注意事项】lseek()允许将文件偏移量设置在文件末尾之外(但这不会改变文件的大小)。如果稍后在此时写入数据,则后续读取间隙( a “hole”)中的数据将返回空字节('\0'),直到读到数据实际写入的位置为止。
2. 使用实例
/* 头文件 */
#include <stdio.h>
/* read write close函数 */
#include <unistd.h>
/* open 函数 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* strlen 函数 */
#include <string.h>
void test_none_lseek();
void test_lseek();
int main(int argc,char*argv[])
{
// test_none_lseek();
test_lseek();
return 0;
}
/**
* @Function:
* @Description: 写入数据后,直接读取,会发现什么也读不到,原因就在于写入完毕后,文件指针移动到了文件末尾。
*/
void test_none_lseek()
{
/* 定义一个文件描述符变量 */
int fd;
char buff[32]= "fanhualuojin";
char a[32];
int ret;
/* 1. 打开当前路径下文件 */
fd = open("03lseek.txt",O_RDWR | O_CREAT | O_APPEND, 0666);
/* 2. 判断是否打开成功 */
if(fd < 0)
{
printf("open file err\n");
return;
}
else
{
printf("sucess,fd=%d\n",fd);
}
/* 3. 写入文件内容 */
ret = write(fd, buff, strlen(buff));
if(ret < 0)
{
perror("write");
close(fd);
return;
}
printf("sucess,write count=%d\n",ret);
/* 4. 读取文件内容 */
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);
/* 5. 关闭文件 */
close(fd);
}
/**
* @Function: off_t lseek(int fd, off_t offset, intt whence);
* @Description: 成功时返回实际写入的字节数;出错时返回EOF
*/
void test_lseek()
{
/* 定义一个文件描述符变量 */
int fd;
char buff[32]= "fanhualuojin";
char a[33];
int ret;
/* 1. 打开当前路径下文件 */
fd = open("03lseek.txt",O_RDWR | O_CREAT | O_APPEND, 0666);
/* 2. 判断是否打开成功 */
if(fd < 0)
{
printf("open file err\n");
return;
}
else
{
printf("sucess,fd=%d\n",fd);
}
/* 3. 写入文件内容 */
ret = write(fd, buff, strlen(buff));
if(ret < 0)
{
perror("write");
close(fd);
return;
}
printf("sucess,write count=%d\n",ret);
/* 4. 设置文件指针位置 */
lseek(fd, 0, SEEK_SET);
/* 5. 读取文件内容 */
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);
/* 6. 关闭文件 */
close(fd);
}在终端执行以下命令编译程序:
gcc test.c -Wall # 生成可执行文件 a.out
./a.out # 执行可执行程序