本文谢绝转载,原文来自http://990487026.blog.51cto.com


Linux系统开发
	文件操作
		ext2文件系统了解
		stat()函数
		access()函数
		chmod()函数
		utime()函数
		truncate()函数
		link()硬链接函数
		symlink()软链接函数
		readlink()函数
		unlink函数
		rename函数()
	目录操作
		chdir()/fchdir()
		getcwd/getwd()/get_current_dir_name()
		pathconf()
		opendir()  
		readdir()
		dup()/dup2()

	练习:	

深入解析 ext2 文件系统



stat函数获取文件大小

chunli@ubuntu16:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>

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

int main(int argc,char **argv)
{
	struct stat s_buf;
	if(argc < 2)
	{
		printf("参数不够\n");
		exit(1);
	}
	if(stat(argv[1],&s_buf) < 0)
	{
		perror("stat");
		exit(2);
	}
	printf("文件名:%s\n",argv[1]);
	printf("文件大小:%ld字节 \n",s_buf.st_size);
	
}
//   int stat(const char *pathname, struct stat *buf);
//   int fstat(int fd, struct stat *buf);
//   int lstat(const char *pathname, struct stat *buf);
//   lstat不跟踪符号链接
//
// 	struct stat {
//		dev_t	 st_dev;		 /* ID of device containing file */
//		ino_t	 st_ino;		 /* inode number */
//		mode_t	st_mode;		/* protection */
//		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;	 /* blocksize 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
//	};
//


chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out main.c 
文件名:main.c
文件大小:1454字节 
chunli@ubuntu16:~/linux_c$



access()文件访问函数,测试文件是否存在程序

chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out main.c 
./main.c 存在
chunli@ubuntu16:~/linux_c$ 
chunli@ubuntu16:~/linux_c$ 
chunli@ubuntu16:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>

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

int main(void)
{
	if(access("./main.c",F_OK) < 0)
	{
		perror("open ./haha.txt");
		exit(1);
	}
	printf("./main.c 存在\n");
	
}
//	int access(const char *pathname, int mode);
//	The mode specifies the accessibility check(s) to be performed, 
//	and is either the value F_OK, or a mask consisting of the bitwise
//	 OR of one or more of R_OK, W_OK,and X_OK. F_OK tests for the
//	 existence of the file.  R_OK, W_OK, and X_OK test whether the
//	 file exists and grants read, write, and execute permissions,  respec‐tively.

//RETURN VALUE:      
//	On success (all requested permissions granted, 
//	or mode is F_OK and the file exists), zero is returned.
//	On error (at least one bit in mode asked for a permission ,
//	that is denied, or mode is F_OK and the file does not exist, 
//	or some other error occurred), -1 is returned, and errno is set appropriately.

chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out main.c 
./main.c 存在
chunli@ubuntu16:~/linux_c$



黏住位:用户以root权限执行

chunli@ubuntu16:~$ ll /usr/bin/passwd 
-rwsr-xr-x 1 root root 53K 3月  29 17:25 /usr/bin/passwd*


chmod()函数

chunli@ubuntu16:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>

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

int main(int argc,char **argv)
{
	if(argc < 3)
	{
		printf("参数不够!\n");
	}
	//需要测试文件是否存在
	//"0222" => 转8进制
	int mode = atoi(argv[2]);
	chmod(argv[1],mode);
}
//需要完善的地方:
//1 字符串转8进制
//2 判断文件是否存在才应该去chmod

chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out file 111
chunli@ubuntu16:~/linux_c$ ll
总用量 16K
-rwxrwxr-x 1 chunli chunli 8.5K 8月   4 09:59 a.out*
---xr-xrwx 1 chunli chunli    0 8月   4 09:55 file*
-rw-rw-r-- 1 chunli chunli  435 8月   4 09:59 main.c
chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out file 511
chunli@ubuntu16:~/linux_c$ ll
总用量 16K
-rwxrwxr-x 1 chunli chunli 8.5K 8月   4 10:00 a.out*
-rwxrwxrwx 1 chunli chunli    0 8月   4 09:55 file*
-rw-rw-r-- 1 chunli chunli  435 8月   4 09:59 main.c
chunli@ubuntu16:~/linux_c$



utime()更新文件时间函数

//    #include <sys/types.h>
//    #include <utime.h>
//
//    int utime(const char *filename, const struct utimbuf *times);
//
//    #include <sys/time.h>
//
//    int utimes(const char *filename, const struct timeval times[2]);


truncate()函数,截断文件

//       #include <unistd.h>
//       #include <sys/types.h>
//
//       int truncate(const char *path, off_t length);
//       int ftruncate(int fd, off_t length);



2.7.1 link

wKiom1ejVjCDjm2-AAFgRk2DdM4373.png

创建一个硬链接

当rm删除文件时,只是删除了目录下的记录项和把inode硬链接计数减1,当硬链接计数

减为0时,才会真正的删除文件。

#include <unistd.h>

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

* 硬链接通常要求位于同一文件系统中,POSIX允许夸文件系统

* 符号链接没有文件系统限制

* 通常不允许创建目录的硬链接,某些unix系统下超级用户可以创建目录的硬链

* 创建目录项以及增加硬链接计数应当是一个原子操作


2.7.2 symlink

int symlink(const char *oldpath, const char *newpath)

2.7.3 readlink

读符号链接所指向的文件名字,不读文件内容

ssize_t readlink(const char *path, char *buf, size_t bufsiz)

2.7.4 unlink

int unlink(const char *pathname)

1. 如果是符号链接,删除符号链接

2. 如果是硬链接,硬链接数减1,当减为0时,释放数据块和inode

3. 如果文件硬链接数为0,但有进程已打开该文件,并持有文件描述符,则等该进程关闭该文件时,kernel才真正

去删除该文件

4. 利用该特性创建临时文件,先open或creat创建一个文件,马上unlink此文件


rm 底层也是调用unlink函数




2.8 rename

文件重命名

#include <stdio.h>

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

2.9 chdir

#include <unistd.h>

int chdir(const char *path);

int fchdir(int fd);

改变当前进程的工作目录

2.10 getcwd

获取当前进程的工作目录

#include <unistd.h>

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

chdir(),getcwd()
       char *getcwd(char *buf, size_t size);//用户自己定义字符数组
       char *getwd(char *buf);		//没有数组大小检查
       char *get_current_dir_name(void);//函数静态数组或者堆空间


获取文件路径 

    
chunli@ubuntu16:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>

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

int main(int argc,char **argv)
{
	char buf [10] = {0};
	chdir("/home");
	getcwd(buf,sizeof(buf));
	printf("%s \n",buf);
}

chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out file 511
/home 
chunli@ubuntu16:~/linux_c$



pathconf 文件配置信息

#include <unistd.h>

long fpathconf(int fd, int name);

long pathconf(char *path, int name);

chunli@ubuntu16:~/linux_c$ cat main.c 
#include <stdio.h>
#include <stdlib.h>

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

int main(int argc,char **argv)
{
	printf("%ld\n",fpathconf(STDOUT_FILENO,_PC_NAME_MAX));
	printf("%ld\n",pathconf("./main.c",_PC_NAME_MAX));
	return 0;
}

chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out file 511
255
255
chunli@ubuntu16:~/linux_c$




opendir()  readdir() 目录遍历

struct dirent
struct stat

chunli@ubuntu16:~/linux_c$ cat main.c 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#define MAX_PATH 1024
/* dirwalk: apply fcn to all files in dir */
void dirwalk(char *dir, void (*fcn)(char *))	//遍历目录
{
	char name[MAX_PATH];
	struct dirent *dp;
	DIR *dfd;
	if ((dfd = opendir(dir)) == NULL) 	//如果打开目录失败
	{
		fprintf(stderr, "dirwalk: can't open %s\n", dir);
		return;
	}
	while ((dp = readdir(dfd)) != NULL) 	//读取目录内容
	{
		if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
		{
			continue; /* skip self and parent */
		}
		if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name))// 杠与0"/home/chunli\0"
		{
			fprintf(stderr, "dirwalk: name %s %s too long\n",dir, dp->d_name);
		}
		else 
		{
			sprintf(name, "%s/%s", dir, dp->d_name);
			(*fcn)(name);
		}
	}
	closedir(dfd);
}
/* fsize: print the size and name of file "name" */
void fsize(char *name)	//显示文件的大小
{
	struct stat stbuf;
	if (stat(name, &stbuf) == -1) 
	{
		fprintf(stderr, "fsize: can't access %s\n", name);
		return;
	}
	if ((stbuf.st_mode & S_IFMT) == S_IFDIR)	//判断是不是目录
	{
		dirwalk(name, fsize);	//如果是目录就递归
	}
	printf("%8ld字节 %s\n", stbuf.st_size, name);
}
int main(int argc, char **argv)
{
	if (argc == 1) /* default: current directory */
	{
		fsize(".");
	}
	else
	{
		while (--argc > 0)	//这样做,可以把程序后面的参数全部遍历
		{
			fsize(*(++argv));
		}
	}
	return 0;
}
chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out ../linux_c/
       0字节 ../linux_c//file
    1504字节 ../linux_c//main.c
   12288字节 ../linux_c//.main.c.swp
    9232字节 ../linux_c//a.out
    4096字节 ../linux_c/
chunli@ubuntu16:~/linux_c$



dup/dup2

#include <unistd.h>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

dup和dup2都可用来复制一个现存的文件描述符,使两个文件描述符指向同一个file结

构体。如果两个文件描述符指向同一个file结构体,File Status Flag和读写位置只保存一

份在file结构体中,并且file结构体的引用计数是2。如果两次open同一文件得到两个文件

描述符,则每个描述符对应一个不同的file结构体,可以有不同的File Status Flag和读写

位置。请注意区分这两种情况。


chunli@ubuntu16:~/linux_c$ cat main.c 
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
	int fd, save_fd;
	char msg[] = "This is a test\n";
	fd = open("somefile", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
	if(fd<0) {
		perror("open");
		exit(1);
	}
	printf("fd = %d\n",fd);

	save_fd = dup(STDOUT_FILENO);
	printf("save_fd = %d\n",save_fd);
	dup2(fd, STDOUT_FILENO);	//这个步骤会关闭STDOUT_FILENO, fd就是标准输出了
	printf("第3次 fd = %d\n",fd);
	close(fd);
	write(STDOUT_FILENO, msg, strlen(msg));
	dup2(save_fd, STDOUT_FILENO);
	write(STDOUT_FILENO, msg, strlen(msg));
	close(save_fd);
	return 0;
}

chunli@ubuntu16:~/linux_c$ gcc main.c  && ./a.out 
fd = 3
save_fd = 4
This is a test
chunli@ubuntu16:~/linux_c$ cat somefile 
第3次 fd = 3
This is a test
chunli@ubuntu16:~/linux_c$



2.14 练习

1. 实现ls -l功能,可以解析文件权限位。

2. 实现ls -l功能,可以解析出文件所有者和文件所有组。(偏难)

3. 实现rm删除命令,如

rm file

rm directory

*注意,千万不要在你有代码的目录下做测试,防止删除你的有用文件,友情提示(rmdir/unlink和递归遍历目

录)

4. 从文件里面读出1000个随机数,进行排序,再写到另一文件中。(考虑使用重定向dup/dup2)