文本文件:文件中的内容都是由文本构成的,文本指的是ASCII码,Unicode码,utf8码等字符。其实,这些字符码的本质是数字(无论什么编码格式,对应的都是二级制的0和1)。
常见的.c文件.h文件.txt文件等都是文本文件,其好处是可以被人轻松的编写和理解。
二进制文件:二进制文件中存储的也是二进制的0和1,只不过这些数字并不是符合一定编码规则的数字,而是纯粹的数字0和1。
gcc编译生成的a.out文件和arm-linux-gcc编译生成的.bin文件都是二进制文件;
如果区分文本文件和二进制文件呢?在linux系统中,是无法区分的;例如open,read,write等操作文本文件和二进制文件是没有任何区别的。只能通过文件的后缀来区别。
常见的文本编辑器:vi,vim,gedit,notepad++,sourceinsight等这些都属于文本编辑器;当我们使用这些编辑器打开文本文件的时候,编辑器会read出文本文件的二进制内容,然后按照编码格式去解码,将其还原成文本(字符)展现给我们。
但如果用文本文件编辑器打开二进制文件时,看到的结果是乱码!(或者使用不符合编码解码规则的文件时,打开也是乱码)。
反过来使用二进制阅读工具读取文本文件时,得到的就是文本文件中编码字符所对应的二进制数字。
目录就是文件夹,文件夹是一种页数的文件!
使用vi打开一个文件夹,就可以看到如下信息,里面包含文件路径和文件列表;但是文件夹比较特殊,不适合用普通的方式(read,write)来读写操作;linux中使用特殊的API来专门读写文件夹。
设备文件对应的是“设备”,设备文件虽然存在与linux系统中,但是设备文件并不存在于硬盘上,而是linux文件系统虚拟制造出来的(叫做虚拟文件系统,如/dev /sys /proc)。
虚拟文件中的大多数不能直接读写,而是用一些特殊的API使用,详见linux驱动编写部分。
使用管道作为通信方式时,会使用的到管道文件。
linux网络的基础
符号连接文件是一种快捷方式!!!
ln-s 软连接?软连接相当于是一个快捷方式,因此其inode与源文件不同;
ln硬连接?硬连接的inode与源文相同;
0777就是rwx-rwx-rwx
size文件大小;Blocks占用了多少块;
IOBlocks该文件在被读写时,其内部的块的大小(linux系统操作缓冲区向硬盘写入数据的单位大小);
regular file:该文件属于普通文件;
Device:该文件所存放在的设备;(类似设备名,扇区名)
Inode:静态文件存储在硬盘里时的编号;一个文件分配一个Inode,linux系统中有多少文件就有多少个Inod;
Links:该文件的硬连接数;
Access:该文件的可访问性;可读可写可执行;
Uid:用户id;root组
Gid:文件分为哪一组;root组
Access:最后访问时间,打开,读,写;
Modify:文件内容最后被修改的时间;
Change:文件属性最后被修改的时间。
文件属性信息查看的API有三个,stat,fstat,lstat,三个作用一样,参数不同,细节略有不同;
man 1 普通文件; man 2 系统调用 ; man 3 库函数;
linux命令行下可以使用stat命令去查看文件的属性信息,实际上stat命令内部就是使用stat系统调用来实现的;
stat这个API的作用就是让内核将文件的属性信息结构体的值放入我们传递给stat函数的buf中,当stat这个API调用从内核返回的时候buf中就被填充了文件的正确的属性信息,然后我们通过查看buf这种结构体变量的元素的值就可以得知文件的属性。
向内核传递一个空白的结构体,该结构体从内核中带出来的信息,就是我们想要的信息!!!
SYNOPSIS
#include
#include
#include
int stat(const char *pathname, struct stat *buf);//以文件名为入口
int fstat(int fd, struct stat *buf);//以文件操作符为入口
int lstat(const char *pathname, struct stat *buf);//以文件名为入口
fstat是从一个已经打开的文件的fd得到文件属性信息,fstat是从内存中读取动态文件的属性信息的,因此效率更高;
stat是从文件名获得文件信息,适用于未被打开的文件,stat是从磁盘获取文件属性信息的;
lstat与“fstat和stat”的区别:对于符号连接文件,lstat查阅的是符号连接文件本身的文件属性信息(快捷方式文件自身的文件属性信息),而stat和fstat查阅的是符号链接文件指向的源文件的文件属性信息!
struct stat是llinux系统内核定义的一个结构体,在
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
};
写个程序查看文件信息:
文件类型就是“普通文件,目录文件,字符设备文件,块设备文件,管道文件,套接字文件,符号连接文件”;
文件属性中的文件类型标志在struct stat的mode_t st_mode元素中,这个元素是一个按位来定义的一个位标志,由很多的标志位共同构成,记录了很多信息,查找是按位&操作就知道结果了,但是由于这些位定义不容易记住,因此linux事先定义好了很多宏来进行操作。
Because tests of the above form are common, additional macros are defined by POSIX to allow the test of the file type in st_mode to be written more concisely:
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.)
例如,S_ISREG宏返回值是1表示这个文件是一个普通文件,如果文件不是普通文件则返回值是0;
#include
#include
#include
#include
#include
#include
#include
#define NAME "1.txt"
int main()
{
int ret=-1;
struct stat buff;
memset(&buff,0,sizeof(buff));//memset后,buff中全部是0;
ret=stat(NAME,&buff);//stat后,buff中有内容了;
if(ret<0)
{
perror("stat");
exit(-1);
}
//判断文件属性
int result=S_ISREG(buff.st_mode);
printf("result is %d\n",result);
return 0;
}
st_mode中除了记录文件类型以外,还记录了“文件权限”;
linux并没有提供对文件权限测试的宏操作,而只提供了掩码,所以我们只能使用位掩码来判断是否具有响应的权限;
The following mask values are defined for the file mode component of the st_mode field:
S_ISUID 04000 set-user-ID bit
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
//属主的权限user
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
//所在组的权限group
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
//other的权限
S_IRWXO 00007 others (not in group) have read, write, and exe‐
cute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
st_mode本质上是一个32位的数,类型是unsigned int,这个数里的每一位表示一个含义;
文件类型和文件权限都记录在st_mode中,我们使用的时候用专门的掩码取出响应的位即可得到响应的信息。
123-456-789,一共9位,3个一组。
第一组三个表示文件的属主(owner或者user,简写u)对该文件的可读、可写、可执行权限;
第二组三个表示文件的属主所在的组(group,简写g)对该文件的可读、可写、可执行权限;
第三组三个表示其他用户(others,简写o)对该文件的可读、可写、可执行权限。
“属主”就是这个文件属于谁,一般来说文件创建时属主就是创建这个文件的那个用户;
在一个文件创建以后,还可以使用chown命令去修改这个文件的属主,也可以使用chgrp命令去修改文件所在的组。
一个程序a.out被执行,a.out试图去操作一个文件1.txt,这时如何判定a.out是否具有对1.txt的某种操作权限呢?
判定方法是:首先1.txt具有9个权限位,依次规定了3种人(user,group,others)对该文件的操作权限。所以我们判定1.txt能否被a.out来操作,首先搞清楚执行a.out的人是属于哪个角色,即a.out被哪种角色的人执行了,也就是当前程序(进程)是哪个用户的进程。
#include
#include
#include
#include
#include
#include
#include
#define NAME "1.txt"
int main(viod)
{
int ret=open(NAME,O_RDONLY);
if(ret>0)
{
printf("可读");
close(ret);
}
else
{
perror("read");
}
ret=open(NAME,O_WRONLY);
if(ret>0)
{
printf("可写");
close(ret);
}
else
{
perror("write");
}
return 0;
}
文件的权限管理并不简单,一般不容易确定对于以个文件是具有某种操作权限。设计优秀的软件,在操作某个文件之前应该自动判断是否具备对该文件的操作权限,如果有权限则执行,没有则应明确提示用户没有操作权限。
access函数可以测试当前执行程序的用户是否具有对目标文件的操作权限。
#include
#include
#include
#include
#include
#include
#include
#define NAME "1.txt"
int main(void)
{
int ret = -1;
ret = access(NAME,F_OK);
if(ret<0)
{
printf("文件不存在!\n");
}
else
{
printf("文件存在OK\n");
}
ret = access(NAME,R_OK);
if(ret<0)
{
printf("文件不可读!\n");
}
else
{
printf("文件可读OK\n");
}
ret = access(NAME,W_OK);
if(ret<0)
{
printf("文件不可写!\n");
}
else
{
printf("文件可写OK\n");
}
return 0;
}
chmod是一个linux命令,用来修改文件的各种权限属性。chmod命令只有root用户才有权利去执行修改。
chmod命令其实内部是用linux的一个叫chmod的API实现的。
#include
#include
#include
#include
#include
#include
#include
#define NAME "1.txt"
int main(int argc , char **argv)
{
int ret = -1;
if(agrc != 2)
{
printf("usage : %s filename\n",argv[0]);
return -1;//不用包含头文件?
}
//chmod成功返回0,失败返回-1
ret=chmod(argv[1],S_IRUSR|S_IWUSR|S_IXUSR);//argv[1]就是filename!!!
if(ret<0)
{
perror("chmod");
return -1;
}
return 0;
}
linux中使用chown命令来修改文件的属主
chown命令是用chown API来实现的。
umask是linux系统中维护的一个全局设置,umask的作用是用来设定我们系统中新建文件的默认权限的。
opendir打开一个目录后得到一个DIR类型的指针给readdir使用;
readdir调用一次就会返回一个struct dirent类型的指针,该指针指向一个结构体变量,这个结构体变量里面记录了一个目录项(目录中的一个子文件);
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
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]; /* filename */
};
redir调用一次只能读取一个目录项,要想读出目录中所有的目录项必须多次调用readdir函数。readdir函数内部记住了哪个目录项已经被读过了哪个还没被读过,所以多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a UNIX domain socket.
DT_UNKNOWN The file type is unknown.
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc,int **argv)
{
DIR *pDir = NULL;
struct dirent *pEnt= NULL;
unsigned count = 0;
if(argc != 2)
{
printf("usage: %s dirname\n",argv[0]);
return -1;
}
pDir = opendir(argv[1]);
if(NULL == pDir)
{
perror("opendir");
}
while(1)
{
pEnt=readdir(pDir);
if(pEnt!=NULL)
{
//还有子文件,再次处理子文件
printf("name : [%s] \n",pEnt->d_name);
count++;
/*
if(pEnt->D_type == DT_REG)
{
printf("是普通文件哦\n");
}
else
{
printf("不是普通文件\n");
}
*/
}
else
{
break;
}
}
printf("总文件书是:%d\n",count);
return 0;
}
有些函数是可重入的,有些是不可重入的;
readdir函数与之前的函数不同之处在于,readdir函数直接返回了一个结构体变量指针,因为readdir内部申请了内存并且给我们返回了地址。多次调用readdir其实readdir内部并不会重复申请内存而是使用第一次调用readdir时分配的那个内存。这个设计方法设计readdir不可重入的关键,
readdir在多次调用时是有关联的,这个关联也表明readdir是不可重入的。
库函数中有一些函数在设计之初是不可重入的,后来意识到这种方式是不安全的,所以重新封装了C库,提供了对应的可重入版本(一般是不可重入函数名_r):readdir(不可重入) readdir_r(可重入)。