Linux的文件系统
目录文件
目录文件的属性保存在inode信息节点中,inode是一个特殊的数据块,同样保存着文件的大小和文件的保存位置。“/”是最高层的目录包含着所有的文件,在根目录下通常包含着“/bin”存放系统程序(binary),“/etc”存放系统的配置文件,“/lib”存在系统库文件,“/dev”存在这系统的设备文件。
文件和设备
即使是硬件设备也都是映射成文件系统的,你可以通过mount将设备挂载到其他文件目录下来访问设备。
/dev/console
这个设备提供系统的控制台,错误信息和诊断通常被发送到这个设备。
/dev/tty
这个特殊的设备是一个控制终端进程的一个别名(键盘,屏幕或者窗体),事实上我们不能控制终端,不能打开/dev/tty,因为进程和脚本都是系统自动调用的。那它用于何处,/dev/tty允许程序输出信息给用户,当标准输出重定向的时候它非常有用。
系统中只有一个/dev/console设备,但是有着很多不同的物理设备通过/dev/tty来访问。
/dev/null
这是一个空设备,所有指向这个设备的输出都会被丢弃。没用的输出通畅都会被重定向到这个设备。
系统调用和磁盘驱动
磁盘驱动封装了硬件依赖特性,一些硬件的特殊特性可以通过ioctl(I/O控制)系统调用。
用于访问磁盘驱动的低级方法 有:
open: 打开一个文件或设备
read:从一个打开的文件或设备读取。
write:向打开的文件或设备写操作。
close:关闭打开了的文件或者设备。
ioctl:向设备驱动传递控制信息。
linux提供了一些高级接口去访问文件和设备。
Low-Level file access
三个默认的描述符: ❑ 0: Standard input
❑ 1: Standard output
❑ 2: Standard error
write
#include <unistd.h>
size_t write(int fildes, const void *buf, size_t nbytes);
向fildes文件描述符中写入nbytes大小的buf数据,size_t 返回实际写入的字节大小,返回0则说明没有写入,返回-1则说明写操作发生了错误,错误信息将返回到errorno的全局变量中。
read
#include <unistd.h>
size_t read(int fildes, void *buf, size_t nbytes);
从fildes描述符中读取nbytes个数据,放入buf。
open 打开一个新的描述符
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);
参数path指向文件的路径,参数oflags表示你要进行的操作,可取参数O_RDONLY:Open for read-only,O_WRONLY:Open for write-only,O_RDWR:Open for reading and writing。还可以用以下的值进行结合:
❑ O_APPEND: Place written data at the end of the file.
❑ O_TRUNC: Set the length of the file to zero, discarding existing contents.
❑ O_CREAT: Creates the file, if necessary, with permissions given in mode.
❑ O_EXCL: Used with O_CREAT, ensures that the caller creates the file. The open is atomic; that is,it’s performed with just one function call. This protects against two programs creating the file at the same time. If the file already exists, open will fail.
初始权限
当你open函数的第二个参数的“O_CREAT”去创建文件时候,将会用到open的第三个参数,这个参数是安位进行OR操作,定义在 sys/stat.h , 它们的值如下:
❑ S_IRUSR: Read permission, owner
❑ S_IWUSR: Write permission, owner
❑ S_IXUSR: Execute permission, owner
❑ S_IRGRP: Read permission, group
❑ S_IWGRP: Write permission, group
❑ S_IXGRP: Execute permission, group
❑ S_IROTH: Read permission, others
❑ S_IWOTH: Write permission, others
❑ S_IXOTH: Execute permission, others
umask P102
close
#include <unistd.h>
int close(int fildes);
用close关闭一个文件描述符,返回0成功,返回-1失败。
ioctl
#include <unistd.h>
int ioctl(int fildes, int cmd, ...);
file descriptors, sockets, and even tape drives可能有ioctl调用,你需要去参考指定的驱动帮助页面。
例如调用ioctl打开kerboard上的LEDs:ioctl(tty_fd, KDSETLED, LED_NUM|LED_CAP|LED_SCR);
管理文件的其他系统函数
lseek 设置read/write文件描述符指针的位置
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes, off_t offset, int whence);
offset:指定位置
whence:指定offset从哪个位置开始计算,可以取值
❑ SEEK_SET: offset is an absolute position
❑ SEEK_CUR: offset is relative to the current position
❑ SEEK_END: offset is relative to the end of the file
返回值:从whence实际移动的位置。
fstat, stat, and lstat
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int fstat(int fildes, struct stat *buf); 返回打开的文件描述符的状态信息,放入stat类型的buf
int stat(const char *path, struct stat *buf); 返回指定路径的文件的状态。
int lstat(const char *path, struct stat *buf); 返回指定路径的文件的状态。
stat和lstat的区别在于当文件是一个链接时,lstat返回链接文件的信息,stat返回的是链接文件所链接到的那个文件的信息。 结构体stat的的成员有:
st_mode File permissions and file-type information
st_ino The inode associated with the file
st_dev The device the file resides on
st_uid The user identity of the file owner
st_gid The group identity of the file owner
st_atime The time of last access
st_ctime The time of last change to permissions, owner, group, or content
st_mtime The time of last modification to contents
st_nlink The number of hard links to the file
st_mode参数也有一些相关联的宏定义在头文件sys/stat.h中,这些宏包含了权限和文件类型帮助我们去测试特殊的类型和权限和一些masks。这些权限参数和前面谈论到的open函数中形容的是一样的,FileType标识有:
❑ S_IFBLK: Entry is a block special device
❑ S_IFDIR: Entry is a directory
❑ S_IFCHR: Entry is a character special device
❑ S_IFIFO: Entry is a FIFO (named pipe)
❑ S_IFREG: Entry is a regular file
❑ S_IFLNK: Entry is a symbolic link
Other mode flags include
❑ S_ISUID: Entry has setUID on execution
❑ S_ISGID: Entry has setGID on execution
Masks to interpret the st_mode flags include
❑ S_IFMT: File type
❑ S_IRWXU: User read/write/execute permissions
❑ S_IRWXG: Group read/write/execute permissions
❑ S_IRWXO: Others’ read/write/execute permissions
例如,测试一个文件是否为目录并且是否只有本人用户才具有执行的权限。
struct stat statbuf;
mode_t modes;
stat(“filename”,&statbuf);
modes = statbuf.st_mode;
if(!S_ISDIR(modes) && (modes & S_IRWXU) == S_IXUSR)
...
dup and dup2 dup用来复制一个文件描述符,返回一个新的文件描述符。dup2有效的复制一个文件描述符到一个指定的文件描述符。这两个方法在多进程通信中很有用。
#include <unistd.h>
int dup(int fildes);
int dup2(int fildes, int fildes2);
标准的I/O库
三个文件流会被自动打开当一个程序开始的时候,他们是stdin,stdout,stderr。
fopen
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
第一个参数为问文件的名字,mode则表明以哪种方式打开文件。可选参数如下(b代表以打开一个二进制的文件):
❑ “r” or “rb”: Open for reading only
❑ “w” or “wb”: Open for writing, truncate to zero length
❑ “a” or “ab”: Open for writing, append to end of file
❑ “r+” or “rb+” or “r+b”: Open for update (reading and writing)
❑ “w+” or “wb+” or “w+b”: Open for update, truncate to zero length
❑ “a+” or “ab+” or “a+b”: Open for update, append to end of file
如果成功,则返回这个文件的指针,否则就是NULL
fread (从流中读取数据)
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
参 数ptr:用于接收数据的地址(指针)
单个元素的大小(size) :单位是字节而不是位,例如读取一个整数值就是4
元素个数(nitems)
提供数据的文件指针(stream)
返回值:成功读取的元素个数
fwrite (向流中写数据)
#include <stdio.h>
size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);
参 数ptr:用于输出数据的地址(指针)
单个元素的大小(size) :单位是字节而不是位,例如输出一个整数值就是4
元素个数(nitems)
输入文件的文件指针(stream)
返回值:成功写入的元素个数
fclose (关闭文件流)
#include <stdio.h>
int fclose(FILE *stream);
fflush (将流缓冲中的数据输出到文件中,close之前都会调用这个函数)
#include <stdio.h>
int fflush(FILE *stream);
fseek (和lseek一样都是定位用的)
#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);
fgetc, getc, and getchar
#include <stdio.h>
int fgetc(FILE *stream); //以字符的形式获取下一个字节,当到文件尾或者发生错误的时候返回EOF,必须通过ferror和feof来 判断这两种情况。
int getc(FILE *stream); //和fgetc一样,但是它是一个宏定义,不能作为一个方法指针
int getchar(); //和getc(stdin)一样,获取标准输入流的下一个字符
fputc, putc, and putchar
#include <stdio.h>
int fputc(int c, FILE *stream); //写一个字符到输入流中,返回以写的值或EOF或failure
int putc(int c, FILE *stream);
int putchar(int c);
fgets, gets
#include <stdio.h>
char *fgets(char *s, int n, FILE *stream); //从输入流中读取一个字符串,最多读取n-1个字符,最后要加上'/0'。如果读取成功,返回一个指向字符串的指针,当读到文件结束EOF的时候,返回一个空指针;如果错误,返回空指针,设置errno的值。
char *gets(char *s); //从标准输入流中读取
格式化的输入输出
printf, fprintf, and sprintf //格式化输出
#include <stdio.h>
int printf(const char *format, ...); //目标标准输出流
int sprintf(char *s, const char *format, ...); //将format输出到一个字符串中,并加上结束符。
int fprintf(FILE *stream, const char *format, ...); //讲format输出啊到一个流中
格式化标准: //还有一些请参考p114
❑ %d, %i: Print an integer in decimal
❑ %o, %x: Print an integer in octal, hexadecimal
❑ %c: Print a character
❑ %s: Print a string
❑ %f: Print a floating-point (single precision) number
❑ %e: Print a double precision number, in fixed format
❑ %g: Print a double in a general format
scanf, fscanf, and sscanf //格式化输入
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);
格式化标准
❑ %d: Scan a decimal integer
❑ %o, %x: Scan an octal, hexadecimal integer
❑ %f, %e, %g: Scan a floating-point number
❑ %c: Scan a character (whitespace not skipped)
❑ %s: Scan a string
❑ %[]: Scan a set of characters (see the following discussion)
❑ %%: Scan a % character
其余方法流
❑ fgetpos: Get the current position in a file stream.
int fgetpos(FILE *stream,*fpos_t filepos);
❑ fsetpos: Set the current position in a file stream.
int fsetpos(FILE *stream, const fpos_t *pos);
❑ ftell: Return the current file offset in a stream.
long ftell(FILE *stream);
❑ rewind: Reset the file position to start in a stream.
void rewind(FILE *stream);
❑ freopen: Reuse a file stream.
FILE *freopen(char *filename, char *type, FILE *stream);
❑ setvbuf: Set the buffering scheme for a stream. //把缓冲区与流相关
int setvbuf(FILE *stream, char *buf, int type, unsigned size);
❑ remove: Equivalent to unlink unless the path parameter is a directory, in which case it’s equivalent to rmdir.
int remove( const char *filename); //删除一个文件
错误流
① 为了指示出错误,好多标准库函数返回一个超出范围的数,好比一个空指针或EOF。在这些例子中这些错误将被指向一个外部变量errno:
#include <errno.h>
extern int errno; //由于很多方法都可以改变这个errno的值,你应该当错误发生的时候就立刻去访问这个值,并且当你用它的时候,你应该把它的值复制到另一个变量中,因为很多输出函数可能会导致errno的改变。
②可以通过访问一个文件流的状态来判断是否出现了错误或者只是EOF。
#include <stdio.h>
int ferror(FILE *stream); //测试流是否出现error,如果是则返回非零值,否则就是0
int feof(FILE *stream); //判断是否到了文件流的EOF,如果是则返回非零值,否则就是0
void clearerr(FILE *stream); //清除文件流指向的EOF和错误指示符。
流和文件描述符
每一个流都和一个低级文件描述符相关
#include <stdio.h>
int fileno(FILE *stream); //查看与流相关的低级文件描述符,成功,返回描述符;失败,-1
FILE *fdopen(int fildes, const char *mode); //在已有的文件描述符上建立一个新的文件流
文件和目录的维护
chmod //改变文件或目录的权限
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
chown //改变文件的拥有者
#include <sys/types.h>
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group); //这个函数设置用户想要的新user和group(culled from getuid and get-gid calls)的数值或者一个系统值来限制所拥有者。
unlink, link, and symlink //删除或建立文件
#include <unistd.h>
int unlink(const char *path); //删除一个文件并且减少它的连接数,返回0,成功;-1,失败。必须有写和执行的权限。如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。如果参数pathname为一符号连接,则此连接会被删除。
int link(const char *path1, const char *path2); //创建一个已存在问价的链接,由path2指定新链接
int symlink(const char *path1, const char *path2); //创建symbolic links,symblic链接不会增加相关的count
mkdir,rmdir
#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode); //创建一个目录,权限被放入到mode中,就想在open函数中设置O_CREATE一样。
#include <unistd.h>
int rmdir(const char *path); //删除一个目录
chdir, getcwd
#include <unistd.h>
int chdir(const char *path); //改变当前的工作目录
char *getcwd(char *buf, size_t size); //输出当前的工作目录到buf中。
浏览目录
关于目录的方法都声明在dirent.h的头文件中,他们用DIR这个结构体对目录进行操作。一个指向这个结构体的指针,叫 directory stream (a DIR *),跟FILE*的作用差不多。目录将自己作为一个dirent结构返回。
opendir //打开一个目录并建立目录流
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); //成功则返回DIR指针,失败则返回空指针。
readdir //读取dirp目录流里面的下一个目录的详细信息
#include <sys/types.h>
#include <dirent.h>
struct dirent *readdir(DIR *dirp); //成功,返回下一个目录实体;失败或读取到最后一个目录,则返回空指针。
dirent结构包含下面的两个实体:
❑ ino_t d_ino: The inode of the file
❑ char d_name[]: The name of the file
telldir //返回目录指针在当前记目录流的位置。
#include <sys/types.h>
#include <dirent.h>
long int telldir(DIR *dirp);
seekdir //设置目录指针在目录流中的位置
#include <sys/types.h>
#include <dirent.h>
void seekdir(DIR *dirp, long int loc); //dirp,目录流; loc,设置的位置
closedir //关闭目录流并释放相关资源
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
错误
strerror,perror
#include <string.h>
char *strerror(int errnum); //strerror方法将一个错误值映射到形容错误的字符串。用于记录错误状态
#include <stdio.h>
void perror(const char *s); //同样将当强的错误映射到一个字符串并且打印到标准错误输出流中。