【1】直接IO (二进制IO)
-
fread
int ch[5];
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件中读按数据类型读去内容(读文件)
参数:
ptr
:读到的内容存放的地址
size
:读一个对应类型所占空间大小sizeof(short)
nmemb
:读多少个元素
stream
:文件流指针
返回值:
成功:读到元素个数
失败或读到文件结尾:0 -
fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:按数据类型将内容写道文件中(写文件)
参数:
ptr
:写内容存放的地址
size
:写元素类型所占空间大小sizeof(short)
nmemb
:写多少个元素
stream
:文件流指针
返回值:
成功:写入元素个数
失败:0
【2】文件指针偏移函数
-
int fseek(FILE *stream, long offset, int whence);
功能:将文件指针偏移到指定的位置
参数:
stream
:流指针
offset
:偏移量 +1:向后偏移一个位置 -1:向前偏移一个位置
whence
:相对位置
SEEK_SET
:文件开头
SEEK_CUR
:当前位置
SEEK_END
:文件结尾
返回值:
成功:0
失败:-1 更新errno -
long ftell(FILE *stream);
功能:获取当前文件指针的位置
(计算文件指针从开头到当前位置的长度)
参数:stream:留置针
返回值:
成功:文件指针当前的位置
失败:-1 更新errno -
void rewind(FILE *stream);
功能:将文件指针定位到文件开头
【3】文件IO
是由posix(可移植操作系统)提供的系统调用函数接口,系统调用基于操作系统,
不同的操作系统向上提供的系统调用函数接口不同。
文件IO是没有缓存机制的,只要进行读写操作就会进行系统调用。
文件IO读写文件是通过文件描述符进行操作
默认情况下,系统已经打开了三个文件描述符:
0、1、2–》标准输入、标准输出、标准出错
文件io可以操作linux下的一切文件类型。
-
文件描述符:
文件描述符是无符号整型的数,它的取值范围是:0~1023,用与去标识打开的一个文件,
后期对文件的操作均通过操作文件描述符实现。 -
文件IO的操作函数
1)open
/close
打开文件/关闭文件
2)read
/write
读文件/写文件
3)lseek
文件指针偏移函数 -
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
:
O_RDONLY
:只读
O_WRONLY
:只写
O_RDWR
:可读可写
O_CREAT
:文件不存在创建 用到创建:mode 是创建权限 0666
O_TRUNC
:文件存在清空
O_APPEND
: 追加
mode
:文件创建权限
返回值:成功:文件描述符
失败:-1,更新errno
用open
函数创建出来的文件的权限:
mode & (~umask)
umask
:权限掩码,用于保护文件
r:O_RDONLY
R+:O_RDWR
w:O_WRONLY | O_CREAT | O_TRUNC,0666
w+:O_RDWR | O_CREAT | O_TRUNC,0666
a:O_WRONLY | O_CREAT | O_APPEND,0666
a+:O_RDWR | O_CREAT | O_APPEND,0666
-
close
#include <unistd.h>
int close(int fd);
功能:关闭文件
参数:fd文件描述符
返回值:成功0
失败-1 更新errno -
read
ssize_t read(int fd, void *buf, size_t count);
功能:读文件
参数:
fd
:文件描述符
buf
:读到内容存放的位置
count
:期待读取的字符个数
返回值:
成功:读到字符个数
失败:-1 更新errno
读到文件结尾:0注意:read读到的字符串后不自动补\0,并且遇到’\n’会继续往后读。
期待读多少个字符就会读多少,如果文件中不够,实际又多少读多少个。对读到的字符串补’\0’:
- 通过read返回的实际读到字符个数,在后边buf[n]=‘\0’;
- 用清零函数
memset
#include <string.h>
void *memset(void *s, int c, size_t n);
s
:要清空的首地址
c
:0
n
: 清空字节数
返回值:清空后空间的首地址
bzero
void bzero(void *s, size_t n);
s
:要清空的首地址
n
: 清空字节数 -
write
ssize_t write(int fd, const void *buf, size_t count);
功能:写文件
参数:fd文件描述符
buf
:写内容的首地址
count
:期待写的字符个数返回值:
成功:实际写入字符的个数
失败:-1 更新errno
练习:文件IO实现cp 功能
/*************************************************************************
> File Name: read.c
> Created Time: Tue 17 Aug 2021 03:22:53 PM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
char str[50];
printf("plz input filename as source\n");
scanf("%s", str);
int fd;
if ((fd = open(str, O_RDONLY)) == -1) {
perror("source");
exit(-1);
}
char str2[50];
printf("plz input filename as target\n");
scanf("%s", str2);
int fd2;
if ((fd2 = open(str2, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
perror("target");
exit(-1);
}
char buf[32] = "";
ssize_t ret;
while ((ret = read(fd, buf, 32))) {
write(fd2, buf, ret);
}
return 0;
}
- lseek
off_t lseek(int fd, off_t offset, int whence);
功能:将文件指针偏移到指定的位置
参数:
fd
:文件描述符
offset
:偏移量
whence
:相对位置
SEEK_SET
:文件开头
SEEK_CUR
:当前位置
SEEK_END
:文件结尾
返回值:
成功:相对与开头偏移的位置
失败:-1 更新errno
【4】获取文件属性 stat
int stat(const char *path, struct stat *buf);
功能:获取文件的属性
参数:
path
:文件路径
buf
:保存文件的相关属性信息
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /*文件类型、文件的权限 */
nlink_t st_nlink; /* 硬链接数*/
uid_t st_uid; /*用户id */
gid_t st_gid; /* 组id */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /*字节大小 */
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_t st_ctime; /* time of last status change */
};
返回值:成功:0
失败:-1,更新errno
文件类型:将st_mode传到宏函数的判断是什么类型的文件
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
getpwuid
getgrgid
作业:
1.用文件io实现图片的复制。
/*************************************************************************
> File Name: cpPhotosByIo.c
> Created Time: Tue 17 Aug 2021 06:44:18 PM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd;
if ((fd = open("nier.png", O_RDONLY)) < 0) {
perror("open.");
exit(-1);
}
int fd2;
if ((fd2 = open("nierNew.png", O_CREAT | O_WRONLY, 0666)) < 0) {
perror("open fd2.");
exit(-1);
}
char buf[32];
size_t size;
while(size = read(fd, buf, 32)) {
write(fd2, buf, size);
}
return 0;
}
2.用标准io的直接iO实现结构体的写入和读出。
/*************************************************************************
> File Name: fread_fwrite.c
> Created Time: Tue 17 Aug 2021 11:24:37 AM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int a;
int b;
}node_t;
int main(int argc, char *argv[])
{
FILE *fp;
if (!(fp = fopen("fread_write.txt", "w+"))) {
perror("fopen.");
exit(1);
}
#if 0
int st[5] = {1, 2, 3, 4, 5};
fwrite(st, sizeof(int), 5, fp);
rewind(fp); //go to base;
int a[5];
fread(a, sizeof(int), 5, fp);
for (int i = 0; i < 5; i++) {
printf("%d\n", a[i]);
}
#endif
node_t st[5];
for (int i = 0; i < 5; i++) {
st[i].a = i;
st[i].b = i*3;
}
fwrite(st, sizeof(node_t), 5, fp);
rewind(fp); //go to base;
node_t a[5];
fread(a, sizeof(node_t), 5, fp);
for (int i = 0; i < 5; i++) {
printf("%d\t%d\n", a[i].a, a[i].b);
}
fclose(fp);
return 0;
}
3.实现:ls -l file
/*************************************************************************
> File Name: ls-lByC.c
> Created Time: Tue 17 Aug 2021 06:59:07 PM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <time.h>
int main(int argc, char *argv[])
{
DIR *dirr = opendir(argv[1]); //all members under dir
struct dirent *dir = NULL; //each member
struct stat sta; //stat can get infomeation of each file
struct passwd *pw; //user name
struct group *gp; //group name
struct tm *ti; //retime
while(dir = readdir(dirr)) {
stat(dir->d_name, &sta); //get each file's information
#if 1
switch (sta.st_mode & S_IFMT) { //file type
case S_IFBLK : putchar('b'); break;
case S_IFCHR : putchar('c'); break;
case S_IFDIR : putchar('d'); break;
case S_IFREG : putchar('-'); break;
case S_IFLNK : putchar('l'); break;
case S_IFSOCK : putchar('S'); break;
case S_IFIFO : putchar('p'); break;
default : putchar('?'); break;
}
#endif
for (int i = 8; i >= 0; i--) {
if(sta.st_mode & (1 << i)) {
switch (i % 3) { //power
case 2 : putchar('r'); break;
case 1 : putchar('w'); break;
case 0 : putchar('x'); break;
}
}
else putchar('-');
}
printf(" %2ld ", sta.st_nlink); //link numbers
pw = getpwuid(sta.st_uid); //user
gp = getgrgid(sta.st_gid); //group
printf("%s %s ", pw->pw_name, gp->gr_name);
printf("%7ld ", sta.st_size); //file size
ti = localtime(&sta.st_mtime);
switch (ti->tm_mon + 1) { //mon
case 1 : printf(" Jan "); break;
case 2 : printf(" Feb "); break;
case 3 : printf(" Mar "); break;
case 4 : printf(" Apr "); break;
case 5 : printf(" May "); break;
case 6 : printf(" Jun "); break;
case 7 : printf(" Jul "); break;
case 8 : printf(" Aug "); break;
case 9 : printf("Sept "); break;
case 10 : printf(" Oct "); break;
case 11 : printf(" Nov "); break;
case 12 : printf(" Dec "); break;
}
printf("%2d ", ti->tm_mday);
if(ti->tm_year == 121) {
printf("%2d:", ti->tm_hour);
if (ti->tm_min < 10) {
printf("0%d ", ti->tm_min);
}
else
printf("%2d ", ti->tm_min);
}
else printf("%5d ", 1900+ti->tm_year);
printf("%s\n", dir->d_name);
}
return 0;
}