1、文件读写
//IO函数测试--->open close read write lseek
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//打开文件
int fd = open(argv[1], O_RDWR | O_CREAT, 0777);//0777表示文件权限
if(fd<0)
{
perror("open error");
return -1;
}
//写文件
//ssize_t write(int fd, const void *buf, size_t count);
write(fd, "hello world", strlen("hello world"));
//移动文件指针到文件开始处
//off_t lseek(int fd, off_t offset, int whence);
lseek(fd, 0, SEEK_SET);
//读文件
//ssize_t read(int fd, void *buf, size_t count);
char buf[1024];
memset(buf, 0x00, sizeof(buf));
int n = read(fd, buf, sizeof(buf));
printf("n==[%d], buf==[%s]\n", n, buf);
//关闭文件
close(fd);
return 0;
}
2、//lseek函数获取文件大小
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//打开文件
int fd = open(argv[1], O_RDWR);
if(fd<0)
{
perror("open error");
return -1;
}
//调用lseek函数获取文件大小
int len = lseek(fd, 0, SEEK_END);
printf("file size:[%d]\n", len);
//关闭文件
close(fd);
return 0;
}
1 文件权限计算方法:
mode & ~umask
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在, 将其长度截断为为0字节。
O_NONBLOCK 对于设备文件, 以O_NONBLOCK方式打开可以做非阻塞I/O(NonblockI/O),非阻塞I/O。
2 思考: 阻塞和非阻塞是文件的属性还是read函数的属性?
通过读普通文件测试得知: read函数在读完文件内容之后, 若再次read,则
read函数会立刻返回, 表明read函数读普通文件是非阻塞的.
//验证read函数读普通文件是否阻塞
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//打开文件
int fd = open(argv[1], O_RDWR);
if(fd<0)
{
perror("open error");
return -1;
}
//读文件
char buf[1024];
memset(buf, 0x00, sizeof(buf));
int n = read(fd, buf, sizeof(buf));
printf("FIRST: n==[%d], buf==[%s]\n", n, buf);
//再次读文件, 验证read函数是否阻塞
memset(buf, 0x00, sizeof(buf));
n = read(fd, buf, sizeof(buf));
printf("SECOND: n==[%d], buf==[%s]\n", n, buf);
//关闭文件
close(fd);
return 0;
}
设备文件: /dev/tty 标准输入STDIN_FILENO
通过读/dev/tty终端设备文件, 表明read函数读设备文件是阻塞的.
//验证read函数读设备文件是阻塞的 标准输入STDIN_FILENO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//读标准输入
char buf[1024];
memset(buf, 0x00, sizeof(buf));
int n = read(STDIN_FILENO, buf, sizeof(buf));
printf("FIRST: n==[%d], buf==[%s]\n", n, buf);
return 0;
}
结论: 阻塞和非阻塞不是read函数的属性, 而是文件本身的属性.
socket pipe这两种文件都是阻塞的.
使用st_mode成员判断文件类型:
if((sb.st_mode & S_IFMT) ==S_IFLNK)
{
printf("连接文件\n");
}
if (S_ISREG(sb.st_mode))
{
printf("普通文件\n");
}
判断文件权限:
if(sb.st_mode & S_IROTH)
{
printf("---R----");
}
lstat和stat函数:函数描述: 获取文件属性
1 对于普通文件来说, lstat函数和stat函数一样
2 对于软连接文件来说, lstat函数获取的是连接文件本身的属性,
stat函数获取的是连接文件指向的文件的属性.
//stat函数测试: 获取文件大小, 文件属主和组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//int stat(const char *pathname, struct stat *buf);
struct stat st;
stat(argv[1], &st);
printf("size:[%d], uid:[%d], gid:[%d]\n", st.st_size, st.st_uid, st.st_gid);
return 0;
}
//stat函数测试: 获取文件类型和权限
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//int stat(const char *pathname, struct stat *buf);
//获取文件属性
struct stat sb;
stat(argv[1], &sb);
//获取文件类型
if ((sb.st_mode & S_IFMT) == S_IFREG)
{
printf("普通文件\n");
}
else if((sb.st_mode & S_IFMT) ==S_IFDIR)
{
printf("目录文件\n");
}
else if((sb.st_mode & S_IFMT) ==S_IFLNK)
{
printf("连接文件\n");
}
if (S_ISREG(sb.st_mode))
{
printf("普通文件\n");
}
else if(S_ISDIR(sb.st_mode))
{
printf("目录文件\n");
}
else if(S_ISLNK(sb.st_mode))
{
printf("连接文件\n");
}
//判断文件权限
if(sb.st_mode & S_IROTH)
{
printf("---R----");
}
if(sb.st_mode & S_IWOTH)
{
printf("---W----");
}
if(sb.st_mode & S_IXOTH)
{
printf("---X----");
}
printf("\n");
return 0;
}
//stat函数测试: 获取文件大小, 文件属主和组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//int stat(const char *pathname, struct stat *buf);
struct stat st;
lstat(argv[1], &st);
printf("size:[%d], uid:[%d], gid:[%d]\n", st.st_size, st.st_uid, st.st_gid);
return 0;
}
目录操作:
1 打开目录 opendir
函数原型: DIR *opendir(const char *name);
函数返回值: 指向目录的指针
函数参数: 要遍历的目录(相对路径或者绝对路径)
2 循环读目录: readdir
函数原型: struct dirent *readdir(DIR *dirp);
函数返回值: 读取的目录项指针
函数参数: opendir函数的返回值
3 关闭目录: closedir
函数原型: int closedir(DIR *dirp);
函数返回值: 成功返回0, 失败返回-1
函数参数: opendir函数的返回值
//目录操作测试: opendir readdir closedir
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
//打开目录
//DIR *opendir(const char *name);
DIR *pDir = opendir(argv[1]);
if(pDir==NULL)
{
perror("opendir error");
return -1;
}
//循环读取目录项
//struct dirent *readdir(DIR *dirp);
struct dirent *pDent = NULL;
while((pDent=readdir(pDir))!=NULL)
{
//过滤掉.和..文件
if(strcmp(pDent->d_name, ".")==0 || strcmp(pDent->d_name, "..")==0)
{
continue;
}
printf("[%s]---->", pDent->d_name);
//判断文件类型
switch(pDent->d_type)
{
case DT_REG:
printf("普通文件");
break;
case DT_DIR:
printf("目录文件");
break;
case DT_LNK:
printf("链接文件");
break;
default:
printf("未知文件");
}
printf("\n");
}
//关闭目录
closedir(pDir);
return 0;
}
dup和dup2函数:
复制文件描述符----详情看图
//测试dup函数复制文件描述符
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//打开文件
int fd = open(argv[1], O_RDWR);
if(fd<0)
{
perror("open error");
return -1;
}
//调用dup函数复制fd
int newfd = dup(fd);
printf("newfd:[%d], fd:[%d]\n", newfd, fd);
//使用fd对文件进行写操作
write(fd, "hello world", strlen("hello world"));
//调用lseek函数移动文件指针到开始处
lseek(fd, 0, SEEK_SET);
//使用newfd读文件
char buf[64];
memset(buf, 0x00, sizeof(buf));
int n = read(newfd, buf, sizeof(buf));
printf("read over: n==[%d], buf==[%s]\n", n, buf);
//关闭文件
close(fd);
close(newfd);
return 0;
}
//使用dup2函数实现标准输出重定向操作
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//打开文件
int fd = open(argv[1], O_RDWR | O_CREAT, 0777);
if(fd<0)
{
perror("open error");
return -1;
}
//调用dup2函数实现文件重定向操作
dup2(fd, STDOUT_FILENO);
printf("ni hao hello world");
close(fd);
//close(STDOUT_FILENO); 不可以写
return 0;
}
fcntl函数:函数描述: 改变已经打开的文件的属性
1 复制文件描述符: int fd = fcntl(oldfd, F_DUPFD, 0);
2 获得和设置文件的flag属性:
int flag = fcntl(fd, F_GETFL, 0);
flag |= O_APPEND;
fcntl(fd, F_SETFL, flag);
3 fcntl函数常用的操作:
3-1 复制一个新的文件描述符:
int newfd = fcntl(fd, F_DUPFD, 0);
3-2 获取文件的属性标志
int flag = fcntl(fd, F_GETFL, 0)
3-3 设置文件状态标志
flag = flag | O_APPEND;
fcntl(fd, F_SETFL, flag)
3-4 常用的属性标志
O_APPEND-----设置文件打开为末尾添加
O_NONBLOCK-----设置打开的文件描述符为非阻塞
//修改文件描述符的flag属性
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//打开文件
int fd = open(argv[1], O_RDWR);
if(fd<0)
{
perror("open error");
return -1;
}
//获得和设置fd的flags属性
int flags = fcntl(fd, F_GETFL, 0);
flags = flags | O_APPEND;
fcntl(fd, F_SETFL, flags);
//写文件
write(fd, "hello world", strlen("hello world"));
//关闭文件
close(fd);
return 0;
}