目录
一.文件IO:
1.打开文件 open
2.读写文件 read write
3.关闭文件 close
1.open
打开文件
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 文件不存在创建
O_TRUNC 文件存在清0
O_APPEND 追加
O_EXCL 文件存在报错
O_NONBLOCK 非阻塞
O_ASYNC 异步IO
..
mode:权限
只要有O_CREAT标识,表示需要加上权限:
rwx rwx rwx
rw- rw- r--
110 110 100
0 6 6 4
返回值:
成功返回文件描述符
失败返回-1
文件描述符:很小的非负整数,而且新的文件描述符总是尚未被使用的最小的非负整数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd = 0;
fd = open("file.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
return 0;
}
练习:
写出标准IO中"r"、"r+"、"w"、"w+"、"a"、"a+"对应的文件IO的打开形式
"r" O_RONLY
"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
0 STDIN_FILENO -> stdin
1 STDOUT_FILENO -> stdout
2 STDERR_FILENO -> stderr
2.close
int close(int fd);
功能:
关闭文件描述符
成功返回0
失败返回-1
3.write
ssize_t write(int fd, const void *buf, size_t count);
功能:
向文件描述符中写入buf开始的count个字节
参数:
fd:文件描述符
buf:写入的数据
count:写入的字节数
返回值:
成功返回写入的字节数
失败返回-1
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(void)
{
int fd = 0;
char tmpbuff[4096] = {"how are you"};
fd = open("file.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
write(fd, "hello world", 11);
write(fd, tmpbuff, strlen(tmpbuff));
close(fd);
return 0;
}
4.read
ssize_t read(int fd, void *buf, size_t count);
功能:
从文件描述符中读取数据到buf开始的空间中,最多读取count个字节
参数:
fd:文件描述符
buf:存放数据空间首地址
count:最多读取的字节数
返回值:
成功返回读取的字节数
读到文件末尾返回0
失败返回-1
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd = 0;
char tmpbuff[4096] = {0};
ssize_t nret = 0;
fd = open("file.txt", O_RDONLY);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
nret = read(fd, tmpbuff, sizeof(tmpbuff));
printf("读到 %ld 个字节\n", nret);
printf("读到内容:%s\n", tmpbuff);
close(fd);
return 0;
}
5.lseek
off_t lseek(int fd, off_t offset, int whence);
功能:
修改文件描述符对应的偏移量
参数:
fd:文件描述符
offset:偏移量
whence:
SEEK_SET:从文件开头开始偏移
SEEK_CUR:从当前位置开始偏移
SEEK_END:从文件末尾开始偏移
返回值:
成功返回当前的偏移量
失败返回-1
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd = 0;
off_t len = 0;
char ch = 0;
fd = open("file.txt", O_WRONLY | O_TRUNC | O_CREAT, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
len = lseek(fd, 10, SEEK_SET);
printf("len = %ld\n", len);
ch = 'a';
write(fd, &ch, 1);
len = lseek(fd, -5, SEEK_CUR);
printf("len = %ld\n", len);
ch = 'b';
write(fd, &ch, 1);
len = lseek(fd, 0, SEEK_SET);
printf("len = %ld\n", len);
ch = 'c';
write(fd, &ch, 1);
close(fd);
return 0;
}
6.标准IO和文件的区别
fopen -> open
fgetc/fputc -> read/write
fgets/fputs
fscanf/fprintf
fread/fwrite
fclose -> close
fseek -> lseek
rewind
ftell
1.标准IO是库函数
2.文件IO是系统调用
3.标准IO是针对于文件IO的封装
4.标准IO是有缓存的
5.文件IO是没有缓存的
6.标准IO主要用于操作普通文件
7.文件IO可以操作设备文件、进程间通信的文件、普通文件(Linux系统下的一切文件均可以使用文件IO)
库函数:是针对于系统调用的封装,可以在Windows或者Linux系统中使用
系统调用:是Linux内核中的函数接口,只能在Linux系统中使用
7.其余函数接口
1.fileno
标准IO -> 文件IO
int fileno(FILE *stream);
功能:
获得文件流指针对应的文件描述符
2.fdopen
文件IO -> 标准IO
FILE *fdopen(int fd, const char *mode);
功能:
通过文件描述符获得文件流指针
3.feof
检测是否读到文件末尾
4.ferror
检测是否出错
5.clearerr
清除错误
二.目录文件
1.目录文件的操作
1. mkdir
int mkdir(const char *pathname, mode_t mode);
功能:
创建目录
参数:
pathname:目录文件的路径
mode:目录文件的权限
返回值:
成功返回0
失败返回-1
注意:
1.r 决定是否目录下可以查看其余文件信息
2.w 决定目录下的文件是否能够新建
3.x 决定目录文件是否能够进入
#include "../head.h"
int main(void)
{
char tmpbuff[4096] = {0};
getcwd(tmpbuff, sizeof(tmpbuff));
printf("当前路径:%s\n", tmpbuff);
chdir("/home/linux/Desktop");// 切换程序当前的工作路径
getcwd(tmpbuff, sizeof(tmpbuff));
printf("当前路径:%s\n", tmpbuff);
mkdir("dirname", 0777);//0777是r w x可读,写,执行
rmdir("dirname");
return 0;
}
2.rmdir
int rmdir(const char *pathname);
功能:
删除空目录文件
参数:
pathname: 目录文件的路径
返回值:
成功返回0
失败返回-1
3.getcwd
char *getcwd(char *buf, size_t size);
功能:
获得当前工作目录的绝对路径
参数:
buf:存放路径空间首地址
size:最大存放字符的长度
返回值:
成功返回存放路径字符串空间首地址
失败返回NULL
4.chdir
int chdir(const char *path);
功能:
切换程序当前的工作路径
参数:
path:目的路径
返回值:
成功返回0
失败返回-1
5.chmod
chmod 0777 filename
chmod 0664 filename
chmod +/-r/w/x filename
int chmod(const char *pathname, mode_t mode);
功能:
修改文件权限
参数:
pathname:文件路径
mode:权限值 0777 0664
返回值:
成功返回0
失败返回-1
2.目录文件的读取
1.操作方法:
打开目录
读取目录项
关闭目录
2.函数接口:
1.opendir
DIR *opendir(const char *name);
功能:
打开目录
参数:
name:目录文件路径
返回值:
成功返回目录流指针
失败返回NULL
#include "../head.h"
int main(void)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
mkdir("dirname", 0777);
fclose(fopen("dirname/a.txt", "w"));
fclose(fopen("dirname/b.txt", "w"));
fclose(fopen("dirname/c.txt", "w"));
fclose(fopen("dirname/d.txt", "w"));
fclose(fopen("dirname/e.txt", "w"));
dp = opendir("dirname");
if (NULL == dp)
{
perror("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
printf("=======================\n");
printf("inode: %ld\n", pp->d_ino);
printf("offset: %ld\n", pp->d_off);
printf("reclen: %d\n", pp->d_reclen);
printf("name: %s\n", pp->d_name);
printf("=======================\n");
}
closedir(dp);
return 0;
}
2.closedir
int closedir(DIR *dirp);
功能:
关闭目录流指针
参数:
dirp:目录流指针
返回值:
成功返回0
失败返回-1
3.readdir
struct dirent *readdir(DIR *dirp);
功能:
读取目录项
参数:
dirp:目录流指针
返回值:
成功返回目录项指针
失败返回NULL
读到末尾返回NULL
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 */
};
路径: ../file.txt
遍历目录文件
#include "../head.h"
int ListDir(char *pdirname)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir(pdirname);
if(NULL == dp)
{
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
printf("pp->d_name = %s/%s\n", pdirname, pp->d_name);
}
closedir(dp);
return 0;
}
int main(void)
{
char dirname[256] = {0};
printf("请输入目录路径:\n");
scanf("%s", dirname);
ListDir(dirname);
return 0;
}
文件名:file.txt
递归遍历目录文件
得到一个目录下的所有子目录,包括这些子目录的子文件的路径,并且得到所用的时间。
#include "../head.h"
int ListDir(char *pdirname)
{
char filepath[1024] = {0};
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir(pdirname);
if (NULL == dp)
{
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
sprintf(filepath, "%s/%s", pdirname, pp->d_name);//获得文件的目录路径,传文件名找不到所以要传目录路径。
printf("%s\n", filepath);
if (DT_DIR == pp->d_type)//判断是不是目录文件
{
ListDir(filepath);
}
}
closedir(dp);
return 0;
}
int main(void)
{
char dirname[256] = {0};
struct timeval start;
struct timeval end;
long ts;
printf("请输入目录路径:\n");
scanf("%s", dirname);
gettimeofday(&start, NULL);
ListDir(dirname);
gettimeofday(&end, NULL);
ts = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec);
printf("耗时 %ld.%ld s\n", ts / 1000000, ts % 1000000);
return 0;
}
三.链接文件
1.软链接(符号链接)
1.symlink
ln -s 要链接向的文件名 软链接文件名(指令)
ln -s b.txt a.txt
a.txt -> b.txt
通过文件名进行链接
普通文件:
文件名 -> inode -> 数据块
软链接:
软连接文件名 -> inode -> 数据块 -> 链接向的文件名 -> inode -> 数据块
int symlink(const char *target, const char *linkpath);(函数)
功能:
创建一个linkpath的软连接文件,里面存放target字符串
参数:
target:链接向的文件名
linkpath:软链接文件名
返回值:
成功返回0
失败返回-1
#include "../head.h"
int main(void)
{
FILE *fp = NULL;
char tmpbuff[4096] = {0};
symlink("file.txt", "a.txt");
fp = fopen("a.txt", "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
fgets(tmpbuff, sizeof(tmpbuff), fp);
printf("%s\n", tmpbuff);
fclose(fp);
memset(tmpbuff, 0, sizeof(tmpbuff));
readlink("a.txt", tmpbuff, sizeof(tmpbuff));
printf("连接文件本身的数据:%s\n", tmpbuff);
return 0;
}
2.readlink
ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
功能:
读取软链接文件本身内容
参数:
path:软链接文件名
buf:存放软链接文件内容的缓冲区
bufsize:缓冲区的大小
返回值:
成功返回读取的字节数
失败返回-1
2.硬链接
ln 要链接的文件名 硬链接文件名 (指令)
通过在磁盘中存放的inode节点进行链接
删除文件链接关系断开
1.link
int link(const char *oldpath, const char *newpath);
功能:
创建一个newpath的硬链接文件
参数:
oldpath:要链接的文件名
newpath:硬链接文件名
返回值:
成功返回0
失败返回-1
2.unlink
int unlink(const char *pathname);
功能:
删除链接文件名,并让硬链接个数-1 ,如果一个磁盘空间硬链接个数为0,需要回收磁盘空间
参数:
pathname:链接文件名
返回值:
成功返回0
失败返回-1
3.stat和lstat
int lstat(const char *pathname, struct stat *statbuf);
功能:
获得pathname对应文件的详细信息
参数:
pathname:文件路径(是文件路径不是文件名)
statbuf:存放文件详细信息空间的首地址
返回值:
成功返回0
失败返回-1
将目录文件的下的所有文件显示详细信息。
int DisplayFile(char *pfilename)
{
struct stat buf;
int ret = 0;
struct passwd *pwd = NULL;
struct group *grp = NULL;
struct tm *ptm = NULL;
char *pmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
ret = lstat(pfilename, &buf);
if (-1 == ret)
{
return -1;
}
#if 0
//001 000 000 110 110 100
// 100 000 000
//001 111 000 000 000 000
//001 000 000 000 000 000
printf("buf.st_mode = %#o\n", buf.st_mode);
switch (buf.st_mode & S_IFMT)
{
case S_IFSOCK:putchar('s');break;
case S_IFLNK:putchar('l');break;
case S_IFREG:putchar('-');break;
case S_IFBLK:putchar('b');break;
case S_IFCHR:putchar('c');break;
case S_IFIFO:putchar('p');break;
}
#endif
if (S_ISREG(buf.st_mode))
{
printf("-");
}
else if (S_ISDIR(buf.st_mode))
{
printf("d");
}
else if (S_ISCHR(buf.st_mode))
{
printf("c");
}
else if (S_ISBLK(buf.st_mode))
{
printf("b");
}
else if (S_ISFIFO(buf.st_mode))
{
printf("p");
}
else if (S_ISSOCK(buf.st_mode))
{
printf("s");
}
else if (S_ISLNK(buf.st_mode))
{
printf("l");
}
buf.st_mode & S_IRUSR ? putchar('r') : putchar('-');
buf.st_mode & S_IWUSR ? putchar('w') : putchar('-');
buf.st_mode & S_IXUSR ? putchar('x') : putchar('-');
buf.st_mode & S_IRGRP ? putchar('r') : putchar('-');
buf.st_mode & S_IWGRP ? putchar('w') : putchar('-');
buf.st_mode & S_IXGRP ? putchar('x') : putchar('-');
buf.st_mode & S_IROTH ? putchar('r') : putchar('-');
buf.st_mode & S_IWOTH ? putchar('w') : putchar('-');
buf.st_mode & S_IXOTH ? putchar('x') : putchar('-');
printf(" %ld", buf.st_nlink);
pwd = getpwuid(buf.st_uid);
printf(" %s", pwd->pw_name);
grp = getgrgid(buf.st_gid);
printf(" %s", grp->gr_name);
printf(" %ld", buf.st_size);
ptm = localtime(&buf.st_mtime);
printf(" %s %d %02d:%02d", pmon[ptm->tm_mon], ptm->tm_mday, ptm->tm_hour, ptm->tm_min);
printf(" %s\n", pfilename);
return 0;
}
int main(void)
{
char filename[256] = {0};
printf("请输入文件名\n");
scanf("%s", filename);
DisplayFile(filename);
return 0;
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_sec
#define st_ctime st_ctim.tv_sec
};
#include "../head.h"
int DisplayFile(char *pfilepath)
{
struct stat buf;
int ret = 0;
ret = lstat(pfilepath, &buf);
if (-1 == ret)
{
return -1;
}
switch (buf.st_mode & S_IFMT)
{
case S_IFREG:putchar('-');break;
case S_IFSOCK:putchar('s');break;
case S_IFLNK:putchar('l');break;
case S_IFBLK:putchar('b');break;
case S_IFDIR:putchar('d');break;
case S_IFCHR:putchar('c');break;
case S_IFIFO:putchar('p');break;
}
putchar(' ');
printf("%ld ", buf.st_nlink);
printf("%d ", buf.st_uid);
printf("%d ", buf.st_gid);
printf("%ld ", buf.st_size);
printf("%ld ", buf.st_mtime);
printf("%s\n", pfilepath);
return 0;
}
int main(void)
{
char filepath[256] = {0};
printf("请输入文件路径:\n");
scanf("%s", filepath);
DisplayFile(filepath);
return 0;
}
4.getpwuid
struct passwd *getpwuid(uid_t uid);
功能:
根据uid获得用户信息
参数:
uid:用户的ID号
返回值:
成功返回包含用户信息的结构体指针
失败返回NULL
5.getgrgid
struct group *getgrgid(gid_t gid);
功能:
根据组名获得组ID
参数:
gid:组的ID号
返回值:
成功返回包含组信息结构体指针
失败返回NULL
作业:
1./proc目录下保存的是操作系统中进程相关的信息,该目录下纯数字组成的文件名表示进程的ID,请根据所学知识
将所有正在运行的进程的ID号,及进程总数记录到一个叫做proc.txt的文件中
#include "../head.h"
int IsProcFile(char *pfilename)
{
char *ptmp = pfilename;
int ret = 1;
while (*ptmp != '\0')
{
if (*ptmp < '0' || *ptmp > '9')
{
ret = 0;
break;
}
ptmp++;
}
return ret;
}
int RecordCurrentProcIds(char *procfile)
{
//1.遍历/proc目录
DIR *dp = NULL;
struct dirent *pp = NULL;
FILE *fp = NULL;
int cnt = 0;
fp = fopen(procfile, "w");
if (NULL == fp)
{
return -1;
}
dp = opendir("/proc");
if (NULL == dp)
{
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
if (IsProcFile(pp->d_name))
{
fprintf(fp, "%s\n", pp->d_name);
cnt++;
}
}
closedir(dp);
//2.找到纯数字组成的文件名
//3.写入到文件中
fprintf(fp, "共 %d 个进程\n", cnt);
fclose(fp);
return 0;
}
int main(void)
{
RecordCurrentProcIds("proc.txt");
return 0;
}
6.目录的遍历和递归遍历
目录遍历(当前目录下的所有文件或者目录)
#include "../head.h"
int ListDir(char *pdirname)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
//1.打开目录文件
dp = opendir(pdirname);
if (NULL == dp)
{
return -1;
}
//2.读取目录项
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
printf("pp->d_name:%s\n", pp->d_name);
}
//3.关闭目录文件
closedir(dp);
return 0;
}
int main(void)
{
char dirname[256] = {0};
scanf("%s", dirname);
ListDir(dirname);
return 0;
}
递归遍历(当前目录下的所有文件以及子目录下的所有文件)
#include "../head.h"
int ListDir(char *pdirname)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
char filepath[1024] = {0};
//1.打开目录文件
dp = opendir(pdirname);
if (NULL == dp)
{
return -1;
}
//2.读取目录项信息
//3.如果为目录文件
//4.递归调用遍历此目录文件
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
sprintf(filepath, "%s/%s", pdirname, pp->d_name);
printf("%s\n", filepath);
if (DT_DIR == pp->d_type)
{
ListDir(filepath);
}
}
//5.关闭目录文件
closedir(dp);
return 0;
}
int main(void)
{
char dirname[256] = {0};
scanf("%s", dirname);
ListDir(dirname);
return 0;
}
=========================================================================================
1.Linux系统中时间的获取:
1.time
time_t time(time_t *tloc);
功能:
返回1970年1月1日到现在的秒数
参数:
tloc:存放秒数空间的首地址
返回值:
成功返回1970年1月1日到现在的秒数
失败返回-1
2.localtime
struct tm *localtime(const time_t *timep);
功能:
将秒数转换为本地时间
参数:
timep:存放秒数空间的首地址
返回值:
成功返回本地时间
失败返回NULL
打印输出的时候年要减去1970,月要加1(数组下标的原因);
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
3.mktime
time_t mktime(struct tm *tm);
功能:
根据日历时间转换为1970年1月1日到现在的秒数