文件IO的概念:
什么是文件IO,又称系统IO,系统调用
是操作系统提供的API接口函数。
POSIX接口 (了解)
注意:文件IO不提供缓冲机制
文件IO的API
open close read read
文件描述符概念:
英文:缩写fd(file descriptor)
是0-1023的数字,表示文件。
0, 1, 2 的含义 标准输入,标准输出,错误
文件IO 打开
open
int open(const char *pathname, int flags); 不创建文件
int open(const char *pathname, int flags, mode_t mode); 创建文件,不能创建设备文件
成功时返回文件描述符;出错时返回EOF
成功时返回文件描述符;出错时返回EOF
打开文件时使用两个参数
创建文件时第三个参数指定新文件的权限,(只有在建立新文件时有效)此外真正建文件时的权限会受到umask 值影响,实际权限是mode-umaks
可以打开设备文件,但是不能创建设备文件(创建设备mknode 驱动部分会讲)
文件IO和标准的模式对应关系:
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
原型 | int open(const char *pathname, int flags, mode_t mode); | ||
参数 | pathname | 被打开的文件名(可包括路径名)。 | |
flags | O_RDONLY:只读方式打开文件。 | 这三个参数互斥 | |
O_WRONLY:可写方式打开文件。 | |||
O_RDWR:读写方式打开文件。 | |||
O_CREAT:如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限。 | |||
O_EXCL:如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。 | |||
O_NOCTTY:使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。 | |||
O_TRUNC:如文件已经存在,那么打开文件时先删除文件中原有数据。 | |||
O_APPEND:以添加方式打开文件,所以对文件的写操作都在文件的末尾进行。 | |||
mode | 被打开文件的存取权限,为8进制表示法。 |
umask概念:
umask 用来设定文件或目录的初始权限
文件和目录的真正初始权限
文件或目录的初始权限 = 文件或目录的最大默认权限 - umask权限
文件的关闭
int close(int fd)
关闭后文件描述符不能代表文件
成功时返回0;
出错时返回EOF 程序结束时自动关闭所有打开的文件
文件关闭后,文件描述符不再代表文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[]){
int fd;
int ret;
fd = open("test.txt",O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(fd<0){
printf("open file err\n");
return 0;
}
printf("sucess,fd=%d\n",fd);
ret= close(fd);
if(ret<0){
printf("close failed\n");
}
ret=close(fd);
printf("ret=%d\n",ret);
}
文件IO的读写和定位
read函数用来从文件中读取数据:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
成功时返回实际读取的字节数;出错时返回EOF
读到文件末尾时返回0 buf是接收数据的缓冲区
count不应超过buf大小
write函数用来向文件写入数据:
#include <unistd.h>
ssize_t write(int fd, void *buf, size_t count);
成功时返回实际写入的字节数;出错时返回EOF
buf是发送数据的缓冲区
count不应超过buf大小
容易出错点:
求字符串长度使用sizeof,对二进制数据使用strlen
printf 的字符最后没有’\0’
lseek函数用来定位文件:
#include <unistd.h>
off_t lseek(int fd, off_t offset, intt whence);
成功时返回当前的文件读写位置;
出错时返回EOF
参数offset和参数whence同fseek完全一样
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc,char *argv[]){
int fd;
int ret;
char buf[32] = "hello world";
char buf2[32]={0};
fd = open("test.txt",O_RDWR | O_CREAT|O_APPEND, 0666);
if(fd<0){
printf("open file err\n");
return 0;
}
printf("sucess,fd=%d\n",fd);
ret=write(fd,buf,strlen(buf));
if(ret<0){
perror("write");
goto END;
}
printf("write count=%d\n",ret);
lseek(fd,0,SEEK_SET);
ret = read(fd,buf2,32);
if(ret<0){
perror("read");
goto END;
}
buf2[31]=0;//数组最后一位置零,不设置,超出数组范围会显示乱码
printf("read buf2=%s\n",buf2);
END:
close(fd);
}
利用文件IO实现文件的复制
#include <stdio.h>
int main() {
FILE *source_file, *target_file;
int ch;
// 打开源文件和目标文件
source_file = fopen("source.txt", "r");
target_file = fopen("target.txt", "w");
if(source_file==NULL){
perror("fopen");
return 0;
}
if(target_file==NULL){
perror("fopen");
return 0;
}
// 逐个字符读取源文件内容,并写入目标文件
while ((ch = fgetc(source_file)) != EOF) {
printf("ch=%d\n",ch);
fputc(ch, target_file);
}
printf("ch=%d\n",ch);
// 关闭文件
fclose(source_file);
fclose(target_file);
printf("文件复制完成。\n");
return 0;
}
上述代码中,我们使用`fopen`函数打开源文件和目标文件,并以读取模式`"r"`打开源文件,以写入模式`"w"`打开目标文件。然后,我们使用`fgetc`函数逐个字符读取源文件的内容,然后使用`fputc`函数将每个字符写入目标文件。最后,我们使用`fclose`函数关闭文件,并打印出复制完成的提示信息。
请注意,上述代码只适用于文本文件的复制。如果需要复制二进制文件,可以使用二进制模式的读写(如`"rb"`和`"wb"`)。
文件名通过命令行参数指定
如果希望通过命令行参数指定源文件和目标文件名,则可以使用 argc
和 argv
参数来获取命令行参数,并将其作为文件名进行处理。下面是相应的示例代码:
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s <source_file> <target_file>\n", argv[0]);
return 1;
}
FILE *source_file, *target_file;
char ch;
// 打开源文件和目标文件
source_file = fopen(argv[1], "r");
target_file = fopen(argv[2], "w");
if (source_file == NULL || target_file == NULL) {
printf("Failed to open file.\n");
return 1;
}
// 逐个字符读取源文件内容,并写入目标文件
while ((ch = fgetc(source_file)) != EOF) {
fputc(ch, target_file);
}
// 关闭文件
fclose(source_file);
fclose(target_file);
printf("文件复制完成。\n");
return 0;
}
在上述代码中,argc
参数表示命令行参数的数量,argv
参数是一个指向字符指针的数组,其中保存了命令行参数的值。
在 main()
函数中,我们首先检查 argc
的值是否为3,即程序名 + 源文件名 + 目标文件名。如果参数数量不正确,我们打印出正确的用法提示并返回错误代码。
然后,我们使用 fopen
函数根据 argv[1]
和 argv[2]
的值打开源文件和目标文件。
如果文件打开失败,我们打印出失败的提示信息并返回错误代码。否则,我们使用 fgetc
和 fputc
函数来逐个字符读取源文件内容并写入目标文件。
最后,我们使用 fclose
函数关闭文件,并打印出复制完成的提示信息。
注意:上述代码只能用于文本文件的复制。如果需要复制二进制文件,可以使用二进制模式的读写(如 "rb"
和 "wb"
打开文件的方式?
在C语言中,可以使用标准库中的 fopen()
函数来打开文件。fopen()
函数提供了多种模式用于打开文件,这些模式可指定文件的读写权限和操作方式。以下是 fopen()
函数的基本形式:
FILE *fopen(const char *filename, const char *mode);
其中,filename
参数是一个字符串,表示文件的路径和名称。
mode
参数是一个字符串,指定文件的打开模式。以下是常用的文件打开模式:
- "r": 以只读模式打开文件。
- "w": 以写入模式打开文件,如果文件不存在,则创建新文件;如果文件已存在,则清空文件内容。
- "a": 以追加模式打开文件,如果文件不存在,则创建新文件;如果文件已存在,则在文件末尾追加内容。
- "rb": 以二进制只读模式打开文件。
- "wb": 以二进制写入模式打开文件,如果文件不存在,则创建新文件;如果文件已存在,则清空文件内容。
- "ab": 以二进制追加模式打开文件,如果文件不存在,则创建新文件;如果文件已存在,则在文件末尾追加内容。
fopen()
函数返回一个文件指针,可以用于后续的文件读写操作。如果文件无法打开,fopen()
函数将返回 NULL
。
以下是一个示例代码,演示了如何使用 fopen()
函数打开文件:
#include <stdio.h>
int main() {
FILE *file;
file = fopen("example.txt", "r"); // 以只读模式打开文件 "example.txt"
if (file == NULL) {
printf("无法打开文件。\n");
return 1;
}
// 在这里进行文件读写操作...
fclose(file); // 关闭文件
return 0;
}
上述示例中,我们使用 fopen()
函数以只读模式打开了一个名为 "example.txt" 的文件,并进行了错误检查。如果文件打开失败,我们打印出错误提示信息。
在实际操作中,您可以根据需要选择合适的文件打开模式,并在打开文件后进行相应的读写操作。最后,使用
如何判断读到源文件的末尾?
在C语言中,可以使用feof()
函数或fgets()
函数来判断是否读到了源文件的末尾。
- 使用
feof()
函数:该函数可以用于检测文件流上的文件结束符。当文件结束符被读取时,feof()
函数返回非0值(即真);否则,返回0(即假)。
#include <stdio.h>
int main() {
FILE *file = fopen("filename.txt", "r");
if (file == NULL) {
printf("文件打开失败\n");
return 0;
}
char ch;
while (!feof(file)) {
ch = fgetc(file);
if (ch == EOF) {
break;
}
printf("%c", ch);
}
fclose(file);
return 0;
}
- 使用
fgets()
函数:该函数可用于从文件中读取一行字符。当fgets()
函数读取到文件末尾时,返回空指针。
#include <stdio.h>
int main() {
FILE *file = fopen("filename.txt", "r");
if (file == NULL) {
printf("文件打开失败\n");
return 0;
}
char line[100];
while (fgets(line, sizeof(line), file) != NULL) {
printf("%s", line);
}
fclose(file);
return 0;
}
注意:在任何情况下,都应该在读取文件之后及时关闭文件流