Linux系统编程学习笔记(四)文件和目录管理

文件和目录管理:
1、获得文件metadata的Stat家族:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int lstat(const char * restrict path, struct stat * restrict buf);
int stat(const char *restrict path, struct stat * restrict buf);
int fstat(int fd,struct stat *buf);

lstat和stat区别:
对于软链来说:
lstat返回软链本身的状态
stat返回软链所指文件的状态
struct stat:

struct stat{
dev_t st_dev; /*包含文件的设备号*/
ino_t st_ino; /*文件inode序列号 */
mode_t st_mode;/*文件的mode*/
nlink_t st_nlink; /*硬链接的数量*/
uid_t st_uid; /*文件的用户id*/
gid_t st_gid; /*文件的goup id*/
off_t st_size;/*文件大小*/

time_t st_atime;/*最后一次访问时间*/
time_t st_mtime;/*最后一次修改时间*/
time_t st_ctime;/*最后一次状态改变时间*/
}

例子:

#include <stdio.h>
#include <time.h>
#include <sys/stat.h>

int isdirectory(char *path) {
struct stat statbuf;

if (stat(path, &statbuf) == -1)
return 0;
else
return S_ISDIR(statbuf.st_mode);
}

2、文件权限:
设置文件权限的系统调用:

#include <sys/types.h>
#include <sys/stat.h>

int chmod(const char *path, mode_t mode);
int fchmod(int fd,mode_t mode);

成功返回0,失败返回-1,并设置errno:
EACCESS:没有搜索path的权限
EBADF:fd不合法的文件描述符(仅fchmod)
EFAULT:path不合法的指针(仅chmod)
EIO:文件系统内部I/O错误
ELOOP:由于symbolic link导致解析path死循环
ENAMETOOLONG:path太长(仅chmod)
ENOENT:path不存在
ENOME:内存不足
ENOTDIR:不是一个目录(仅chmod)
EPERM:进程不是文件的owner或者缺少CAP_FOWNER能力。
EROFS:文件在只读文件系统中。
chomd:

ret = chmod("./map.png",S_IRUSR | S_IWUSR);
if(ret)
perror("chmod");


int ret;

ret = fchmod(fd, S_IRUSR | S_IWUSR);
if(ret)
perror("fchmod");

3、文件的所有者:
stat结构中st_uid和st_gid提供了文件的所有者和group,一下系统调用可以改变所有者:

#include <sys/types.h>
#include <unistd.h>

int chown(const char *path, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);

chown和lchown区别:chown会follow simbolic link,改变link的目标文件,lchmod改变符号链接本身。
成功过返回0,失败返回-1,并设置errno。

struct group *gr;
int ret;

gr = getgrnam("officers");
if(! gr){
perror("getgrnam");
return 1;
}

ret = chmod("manifest.txt",-1,gr->gr_gid);
if(ret){
perror("chmod");
return 1;
}

设置为root拥有者:

int make_root_owner(int fd){
int ret;

ret = fchown(fd,0,0);
if(ret)
perror("fchown");
return ret;
}

进程需要有CAP_CHOWN能力,也就是必须是root为所有。
4、文件系统Navigation:
1)改变当前的工作目录:

#include <unistd.h>

int chdir(const char *path);
int fchdir(int fd);

将当前的工作目录指定为path。
例子:

char *dir = "/tmp";
if(chdir(dir) == -1)
perror("Failed to change current working directory to /tmp");

2)获得当前工作目录:
getcwd:

#include <unistd.h>

char *getcwd(char *buf, size_t size);

例子:

#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#ifndef PATH_MAX
#define PATH_MAX 255
#endif

int main(void){
char mycwd[PATH_MAX];
if(getcwd(mycwd,PATH_MAX) == NULL){
perror("Failed to get current working directory");
return 1;
}
printf("Current working directory: %s\n",mycwd);
return 0;
}

3)path conf:
   
#include <unistd.h>

long fpathconf(int fd, int name);
long pathconf(const char *path,int name);
sysconf(int name);

5、创建目录:

#include <sys/stat.h>
#include <sys/types.h>

int mkdir(const char *path, mode_t mode);

成功返回0,失败返回-1,并设置好errno。没有可以递归删除与rm -r等价的系统调用。
如果目录非空,失败设置errno为ENOTEMPTY。

int ret;

ret = rmdir("/home/fuliang/test");
if(ret)
perror("rmdir");

6、删除目录:

#include <unistd.h>

int rmdir(const char *path);

成功返回0,失败返回-1
7、文件夹访问:
1)opendir closedir, readdir

#include <dirent.h>
DIR *opendir(const char *dirname);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
void rewinddir(DIR *dirp);

例子:显示pathname下的文件:

#include <dirent.h>
#include <errno.h>
#include <stdio.h>

int main(int argc, char *argv[]){
struct dirent *direntp;
DIR *dirp;

if(argc != 2){
fprintf(stderr,"Usage %s directory_name\n", argv[0]);
}

if((dirp = opendir(argv[1])) == NULL){
perror("Failed to open directory");
return 1;
}

while((direntp = readdir(dirp)) != NULL)
printf("%s\n", direntp->d_name);
while((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}

dirent结构:

struct dirent{
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /*filename*/
};

POSIX仅需要d_name字段,其他的都是可选的或者是linux特有的。可移植性的程序应该只访问
d_name字段。

从Dir可以获得文件描述符:

#define _BSD_SOURCE
#include <sys/types.h>
#include <dirent.h>

int dirfd(DIR *dir);

这个是BSD的一个扩展,并不是POSIX标准。
2)访问文件的状态信息:
lstat、stat

8、硬链接和软链接:
硬链接:两个path指向同一个inode.
软链接:单独的一个文件,里面存储了链接文件的路径。
1)创建和删除一个硬链接:

#include <unistd.h>

int link(const char *path1, const char *path2);
int unlink(const char *path);

为有path1指定的文件创建一个新的目录项。

#include <stdio.h>
#include <unistd.h>

if (link("/dirA/name1","dirB/name2") == -1)
perror("Failed to make a new link in /dirB");

2)创建和删除一个硬链接:

#include <unistd.h>

int symlink(const char *path1, const char *path2);

9、拷贝或者移动文件:
拷贝和移动文件时两个最基本的文件操作任务,可以使用shell命令cp和mv来完成。
1、拷贝文件:
Unix没有提供此操作的系统调用或者库来完成拷贝文件和目录,但可以使用cp命令来手工执行这个任务。
拷贝一个文件src到目标dst,要执行的操作步骤:
1、打开src
2、打开dst,创建如果不存在,清空如果存在。
3、将src读取到内存
4、将从src读取到的内容写入dst
5、继续指导所有内容从src写到dst
6、关闭dst
7、关闭src
如果拷贝一个目录,递归拷贝目录本身及其子目录通过mkdir及其采用上面步骤拷贝文件。
2、移动:
Unix提供了移动文件的系统调用。ANSI C使用这个调用来移动文件,POSIX标准将其用于文件和目录。

#include <stdio.h>

int rename(const char *oldpath, const char *newpath);

将路径名称从oldpath改成newpath,内容和inode没有变化。newpath需要在同一文件系统中。
成功返回0,失败返回-1,并设置errno。
10、创建临时文件:
1)ISO C标准定义了两个标准I/O函数来创建临时文件。

#include <stdio.h>

char *tmpnam(char *ptr); /*返回执行路径的指针*/
FILE *tmpfile(void); /*返回文件指针,错误则为NULL*/

tmpnam每次产生一个不同的合法的路径名字。如果ptr是NULL,生成一个存储在静态区域的名字,
并返回指向它的指针,所以如果连续调用两次会覆盖前一次的tmpname。
如果指定了ptr,则它被假设指向一个数组,并且长度不小于L_tmpnam(<stdio.h>中定义)。
例子:

#include <stdio.h>

int main(void){
char name[L_tmpnam],line[MAXLINE];
FILE *fp;

printf("%s\n",tmpnam(NULL));
tmpname(name);
printf("%s\n",name);

if((fp = tmpfile()) == NULL){
perror("tmpfile");
return 1;
}

fputs("one line of output\n",fp);
rewind(fp);

if(fgets(line,sizeof(line),fp) == NULL){
perror("fgets");
return 1;
}
fputs(line,stdout);

return 0;
}

2)XSI扩展定义了两个另外的方法来操作临时文件:

#include <stdio.h>

char *tempnam(const char *directory, const char *prefix);
int mkstemp(char *template);

tempnam和tmpnam一样,但是可以指定目录和前缀来生成临时文件名。
1、如果环境变量定义了TMPDIR,则使用它作为目录。
2、如果directory不为NULL,则使用它。
3、在<stdio.h>中的P_tmpdir作为目录。
4、本地的目录,通常/tmp被作为临时目录。
前缀prefix如果不为NULL,至少5个字节。
生成的名字是通过malloc动态申请的内存,所以要使用free释放。

#include <stdio.h>

int main(int argc, char *argv[]){
if(argc != 3){
pintf("usage: %s <directory> <prefix>",argv[0]);
return 1;
}

printf("%s\n",tempnam(argv[1][0] != ' ' ? argv[1] : NULL, argv[2][0] != ' ' ? argv[2] : NULL));

return 0;
}

mkstemp和tmpfile类似,只是返回了文件描述符,并且mkstemp生成的临时文件不会自动清除。
path的后六个字符要设置为XXXXXX,通过替换它来生成不同的名字。

参考:
1、《Linux system programming》
2、《Unix system programming》
3、《Advanced Programming in the Unix Environment》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值