C 文件IO
标准IO和文件IO的区别
- 标准IO是c库函数,文件IO是系统调用接口
- 标准IO自带缓冲区,文件IO没有缓冲
- 标准IO的实现还是要依赖文件IO
缓冲区
- 全缓冲:当缓冲区满了或者特定的情况下才会刷新
- 行缓冲:当缓冲区中有了换行\n就会刷新
- 无缓冲:任何东西进入缓冲区马上被刷新走
- 默认:程序结束会刷新缓冲区
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
char buff[1024];
memset( buff, '\0', sizeof( buff ));
fprintf(stdout, "启用全缓冲\n");
setvbuf(stdout, NULL, _IOFBF, 1024);
fprintf(stdout, "这里是 runoob.com\n");
fprintf(stdout, "该输出将保存到 buff\n");
fflush( stdout );
fprintf(stdout, "这将在编程时出现\n");
fprintf(stdout, "最后休眠五秒钟\n");
sleep(5);
return(0);
}
setvbuf
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
//功能:可以更改缓冲区类型(缓冲区可以人为指定)
//返回值:成功返回0,失败返回非0
stream:流,表示要更改缓冲类型的流
buf:缓冲区地址
mode:要改成的缓冲区类型
_IONBF:无缓冲
_IOLBF:行缓冲
_IOFBF:全缓冲
size:要更改buf的大小(单位字节)
perror、errno、stderr
- errno:错误号,用于内核调用完函数后设置调用结果的编号
- perror:输出对应错误号的信息
- stderr:标准出错流 – 无缓冲
标准流
标准输入流:stdin – 0
标准输出流:stdout – 1
标准出错流:stderr – 2
每打开一个终端,都会默认打开这三个流
fflush
int fflush(FILE *stream);
//功能:强制刷新一个流(Linux下不能刷新stdin)
//返回值:成功返回0,失败返回EOF
stream:要刷新的流
标准IO流
打开文件 — fopen()
#include <stdio.h>
FILE *fopen(const char *pathname,const char *mode);
//功能:
//让内核打开一个文件并且标记它
//返回值:
//成功返回流指针,失败返回NULL
//pathname:要打开的文件名(包含路径)
//mode:打开文件的方式(只读、只写...)
//注:如果操作二进制文件,那么打开文件时的方式可以加上b,但是Linux下不区分二进制流和文本流
freopen()
freopen函数则用于关闭一个已经打开的文件,并打开一个新的文件。它需要三个参数:第一个参数是一个字符串,指定要打开的新文件的路径;第二个参数是一个字符串,指定新文件的打开模式;第三个参数是一个已经打开的FILE指针,指向要关闭的文件。
freopen函数常常用于重定向标准输入、输出或错误流。例如,你可以用freopen将stdout重定向到一个文件,这样printf就会将输出写入文件,而不是终端。
#include <stdio.h>
int main() {
FILE* stream = freopen("output.txt", "w", stdout);
if (stream == NULL) {
// Handle error
}
printf("This will be written to output.txt\n");
fclose(stream);
return 0;
}
在这个例子中,`freopen`函数打开了一个名为"output.txt"的文件,并将`stdout`流重定向到这个文件。这样,后续的`printf`调用会将输出写入这个文件,而不是终端。
注意,你应该检查`freopen`的返回值,以确保文件打开成功。在完成文件写入后,你也应该使用`fclose`关闭文件。
关闭流 — fclose()
#include <stdio.h>
int fclose(FILE *stream)
//功能:关闭已经打开的流
//返回值:成功返回0,失败返回EOF
stream:要关闭的流
按字符读 — fgetc()
#include <stdio.h>
int fgetc(FILE *stream);
//功能:从流里面读取一个字符
//返回值:成功返回读到的字符,失败返回EOF
stream:要读的流
按字符写 — fputc()
#include <stdio.h>
int fputc(int c, FILE *stream);
//功能:往流里面写一个字符
//返回值:成功返回写入的字符,失败返回EOF
//fputc 会将参数c 转为unsigned char 后写入参数stream 指定的文件中。
c:要写的字符
stream:要写入的流
按行读 ---- fgets()
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
//功能:读取一行的内容
//返回值:成功返回s的地址,失败返回NULL
s:要把内容读到哪里去(缓冲区)
size:预计要读的字节数
stream:从哪个流读取
//注:fgets是表示遇到了换行符才终止,如果size比一行的数据大,就读完所有内容。size如果比一行数据小,只读size-1个,追加一个'\0',表示没读完。
按行写 — fputs()
#include <stdio.h>
int fputs(const char *s, FILE *stream);
//功能:往一个流里面写一行数据
//返回值:成功返回非负数,失败返回EOF
s:要写入的内容所在的缓冲区
stream:要写入的流
//注:fputs和puts不一样,puts会自动添加一个换行,fputs不添加
按对象读 — fread()
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//功能:从流里面读取内容,内容分了组(对象)
//返回值:成功返回实际读到的对象个数,失败返回EOF
ptr:要把读到内容放在哪个缓冲区
size:每个对象的字节大小
nmemb:预计要读多少个对象
stream:要读的流
//注:size * nmemb不能超过缓冲区(ptr)大小
按对象写 — fwrite()
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
//功能:把缓冲区的内容写入到流里面
//返回值:成功返回实际写入的对象个数,失败返回EOF
ptr:要写入的数据所在的缓冲区
size:每个对象的字节大小
nmemb:预计要写入的对象个数
stream:要写入的流
重定向 — freopen()
FILE *freopen(const char *pathname, const char *mode, FILE *stream);
//功能:打开一个文件并且会产生一个流,stream所表示的流会被替代
//返回值:成功返回流指针,失败返回NULL
pathname:要打开的文件
mode:打开文件的方式
stream:要重定向的流
定位流
fseek
int fseek(FILE *stream, long offset, int whence);
//功能:fseek()用来移动文件流的读写位置。参数stream为已打开的文件指针, 参数offset为根据参数whence来移动读写位置的位移数。
//参数:
whence为下列其中一种:
SEEK_SET:文件开头
The offset is set to offset bytes.
SEEK_CUR:当前位置
The offset is set to its current location plus offset bytes.
SEEK_END:文件末尾
The offset is set to the size of the file plus offset bytes.
SEEK_END将读写位置指向文件尾后再增加offset个位移量。
当whence值为SEEK_CUR 或SEEK_END时, 参数offset允许负值的出现。
//返回值
当调用成功时则返回0, 若有错误则返回-1, errno会存放错误代码。
ftell
long ftell(FILE *stream);
//功能:检索当前光标位置
//返回值:成功返回位置值,失败返回-1
rewind
void rewind(FILE *stream);
//功能:返回文件的开头
//和(void) fseek(stream, 0L, SEEK_SET)功能一样
文件IO
- 不带缓冲
- 不带缓冲指的是每个read和write都调用内核中的相应系统调用
- 不带缓冲的I/O函数不是ANSI C的组成部分,但是是POSIX和XPG3的组成部分
- 通过文件描述符来访问文件
文件描述符
- 是非负整数(共1024个:0-1023)但是0、1、2被系统占用,用户的第一个从3开始
- 对于内核而言,所有打开文件都由文件描述符引用。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。
1.- 文件io:符合常量: 幻数0、1、2应被代换成符号常数STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO。这些常数都定义在头文件<unistd.h>中。
- 标准io是流: 0 :stdin 1: stdout 2: stderr
open
//功能: open, creat - open and possibly create a file or device
//头文件:
#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);
int creat(const char *pathname, mode_t mode);
//参数说明:
const char *pathname:被打开的文件名(可包括路径名)
int flags:(读写三个参数互斥,只允许选择一个)
O_RDONLY:只读方式打开文件。:read only
O_WRONLY:只写方式打开文件。 :write only
O_RDWR: 可读写方式打开文件。:read write
//以下参数和读写参数可以用 '|' 连接使用
O_CREAT:如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限。
O_EXCL:如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。
O_NOCTTY:使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端
O_APPEND:以添加方式打开文件,所以对文件的写操作都在文件的末尾进行。
O_TRUNC:如文件已经存在,那么打开文件时先删除文件中原有数据。(截断式打开:如果文件有内容,先清空文件内容,再打开)
//mode_t mode:文件权限(只有用到O_CREAT 创建文件的时候才有用)
0777
0664
//返回值:
成功:返回对应的文件描述符
失败:-1
close
//功能:close - close a file descriptor
//头文件:
#include <unistd.h>
//函数原型:
int close(int fd);
//参数说明:
int fd:已经打开的要关闭的文件
//返回值:
成功:0
失败:-1 并设置错误码(errno)
read
//功能:
read - read from a file descriptor
//头文件:
#include <unistd.h>
//函数原型:
ssize_t read(int fd, void *buf, size_t count);
//参数说明:
int fd:已经打开的可读文件
void *buf:用于保存读取到的数据---> 注意,可以使用结构体
size_t count:每次读取的字节数
//返回值:
-1:失败
0:读取到文件末尾或文件为空(在网络通信里面表示客户端退出)
大于0:成功读取到数据
write
//功能:
write - write to a file descriptor
//头文件:
#include <unistd.h>
//函数原型:
ssize_t write(int fd, const void *buf, size_t count);
//参数说明:
int fd:已经打开的可写文件
const void *buf:用于写入的数据
size_t count:每次写入的字节数
//返回值:
-1:失败
大于0:成功写入的数据
㊙️注意:read和write在用户与内核交界处会复制一份数据,所以他们值相同,但是不是同一份数据
lseek
//功能:lseek - reposition read/write file offset
//头文件:
#include <sys/types.h>
#include <unistd.h>
//函数原型:
off_t lseek(int fd, off_t offset, int whence);
//参数说明:
int fd: 操作的文件
off_t offset:偏移量 (+n 向后偏移 -n 向前偏移 0 不偏移)
int whence:参考的基准位置
SEEK_SET:文件开头
The offset is set to offset bytes.
SEEK_CUR:当前位置
The offset is set to its current location plus offset bytes.
SEEK_END:文件末尾
The offset is set to the size of the file plus offset bytes.
//返回值:
文件的当前光标位置(按字节数计算)
文件io 和标准io 的区别
| 文件io | 标准io | |
|---|---|---|
| 缓冲 | 无 | 有 |
| 高低级 | linux系统io、低级io | 高级io |
| 操作对象 | 文件描述符 | 流 |
| 能否打开设备文件 | 可以 | 不可以 |
| API | open close read write sleek | fopen fclose fread fwrite fseek fprintf |
目录操作
opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
//返回值:成功返回一个目录流的指针,失败返回NULL
readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
//返回值结构体
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};
//注意是随机读一个,要打印该目录全部文件要用循坏去判断,例子如下
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
//返回值,成功返回0,失败返回-1
文件属性
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
//结构体
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
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; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_
#define st_ctime st_ctim.tv_sec
};
//lstat和stat功能类似,但是lstat可以获取到链接文件本身文件的属性
//返回值,成功返回0,失败返回-1
//参数:
pathname 文件名