Linux笔记三(文件操作)

8 篇文章 0 订阅

文件操作

Linux文件结构

在Linux中,一切(或几乎一切)都是文件

目录

系统使用的是文件的 inode编号 (保存了文件的管理信息,是文件系统中的一个特殊的数据块),目录结构为文件命名仅仅是为了便于人们使用。

目录是用于保存其他文件的节点号和名字的文件。目录文件中的 每个数据项都是指向某个文件节点的链接删除文件名就等于删除与之对应的链接(文件节点号可以通过 ls -i 查看)。可以用 ln 创建指向同一个文件的链接。

删除一个文件时,实质上是删除了该文件对应的目录项,同时指向该文件的链接数减1。当 链接数为0时,就表示该节点以及其指向的数据不再被使用,磁盘上的相应位置就会被标记为可用空间

文件和设备

硬件设备在Linux中通常也被表示(映射)为文件。

挂载命令:mount

比较重要的三个设备文件:

(1)/dev/console
系统控制台。错误信息和诊断信息通常会被发送到这个设备。

(2)/dev/tty
控制终端。

(3)/dev/null
空设备。写向这个设备的输出被丢弃。

设备分为 字符设备块设备。两者的区别在于访问设备时是否需要一次读写一整块。一般情况下,块设备是那些支持某些类型文件系统的设备,例如硬盘。

系统调用和设备驱动程序

用很少量的函数就可以对文件和设备进行访问和控制,这些函数被称为 系统调用,由UNIX(Linux)直接提供,它们也是通向操作系统本身的接口。

操作系统的核心部分,即 内核,是一组 设备驱动程序。它们是一组对系统硬件进行控制的底层接口。

用于访问设备驱动程序的底层函数(系统调用):
open:打开文件或设备。
read:从打开的文件或设备里读数据。
write:向文件或设备写数据。
close:关闭文件或设备。
ioctl:把控制信息传递给设备驱动程序。

库函数

针对输入输出操作直接使用底层系统调用的一个问题是它们的效率非常低:
(1)使用系统调用会影响系统的性能。
(2)硬件会限制底层系统调用一次所能读写的数据块大小。

为了给设备和磁盘文件提供更高层的接口,Linux发行版提供了一系列的标准函数库。它们是一些由函数构成的集合。

底层文件访问

每个运行中的程序被称为 进程(process)

可能通过系统调用open把文件描述符与文件和设备相关联。

write系统调用
#include <unistd.h>
size_t write(int fildes, const void *buf, size_t nbytes);

将缓冲区buf的前nbytes个字节写入与文件描述符fildes关联的文件中,返回实际写入字节数。如果返回-1,就表示出现错误,错误代码保存在全局变量errno里。

read系统调用
#include <unistd.h>
size_t read(int fildes, void *buf, size_t nbytes);

从与文件描述符fildes关联的文件中读入nbytes个字节的数据,并把它们放到数据区buf中。返回实际读入的字节数,返回-1,就表示出现错误。

open系统调用
//在遵循POSIX规范的系统上,不需要包含sys/types.h和sys/stat.h,但在某些UNIX系统上,需要包含
#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);

建立一条到文件或设备的访问路径,成功时返回文件描述符,失败返回-1,并设置errno。

oflags参数是通过命令文件访问模式与其他可选模式相结合(用“|”操作)的方式来指定的。

模式说明
O_RDONLY以只读方式打开
O_WRONLY以中写方式打开
O_RDWR以读写方式打开
可选模式说明
O_APPEND把写入数据追加在文件的末尾
O_TRUNC把文件长度设置为零,丢弃已有的内容
O_CREAT如果需要,就按参数mode中给出的访问模式创建文件
O_EXCL与O_CREAT一起使用,确保调用者创建出文件。可以防止两个程序同时创建同一个文件

任何一个运行中的程序能够同时打开的文件数是有限制的,这个限制通常是由limits.h头文件中的常量OPEN_MAX定义的。

当你使用带有O_CREAT标志的open调用来创建文件时,必须使用有3个参数格式的open调用。第三个参数mode是几个标志按位或后得到的,这些标志在头文件 sys/stat.h 中定义。

mode_t 取值说明
S_IRUSR读权限,文件属主。
S_IWUSR写权限,文件属主。
S_IXUSR执行权限,文件属主。
S_IRGRP读权限,文件所属组。
S_IWGRP写权限,文件所属组。
S_IXGRP执行权限,文件所属组。
S_IROTH读权限,其他用户。
S_IWOTH写权限,其他用户。
S_IXOTH执行权限,其他用户。
close系统调用
#include <unistd.h>
int close(int fildes);

终止描述符fildes与其对应文件之间的关联。成功时返回0,出错时返回-1。

ioctl系统调用
#include <unistd.h>
int ioctl(int fildes, int cmd, ...);

具体设备具体情况。

其他系统调用
lseek系统调用
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes, off_t offset, int whence);

对文件描述符fildes的读写指针进行设置。

offset参数用来指定位置,whence参数定义该偏移值的用法。

参数whence取值说明
SEEK_SEToffset是一个绝对位置(即相当于文件头的相对位置)
SEEK_CURoffset是相对于当前位置的一个相对位置
SEEK_ENDoffset是相对于文件尾的一个相对位置

返回从文件头到文件指针被设置处的字节偏移值,失败时返回-1。

参数offset的类型 off_t 是一个与具体实现有关的 整数 类型,它定义在头文件 sys/types.h 中。

fstat、stat和lstat系统调用
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int fstat(int fildes, struct stat *buf);
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);

返回文件的状态信息,并放入到buf中。

当文件是一个符号链接时,lstat返回的是该符号链接本身的信息,而stat返回的是该链接指向的文件的信息。

struct stat 成员说明
st_mode文件权限和文件类型信息
st_ino与该文件关联的inode
st_dev保存文件的设备
st_uid文件属主的UID号
st_gid文件属主的GID号
st_atime文件上一次被访问的时间
st_ctime文件的权限、属主、组或内容上一次被改变的时间
st_mtime文件的内容上一次被修改的时间
st_nline该文件上硬链接的个数

st_mode标志还有一些与之关联的宏,它们定义在头文件 sys/stat.h 中。这些宏对访问权限、文件类型标志以及一些用于帮助测试特定类型和权限的掩码的定义。

访问权限标志与open一样。

文件类型标志说明
S_IFBLK文件是一个特殊的块设备
S_IFDIR文件是一个目录
S_IFCHR文件是一个特殊的字符设备
S_IFIFO文件是一个FIFO(命名管道)
S_IFREG文件是一个普通文件
S_IFLNK文件是一个符号链接
其他模式标志说明
S_ISUID文件设置了SUID位
S_ISGID文件设置了SGID位
解释st_mode标志的掩码说明
S_IFMT文件类型
S_IRWXU属主的读/写/执行权限
S_IRWXG属组的读/写/执行权限
S_IRWXO其他用户的读/写/执行权限
帮助确定文件类型的宏定义说明
S_ISBLK测试是否是特殊的块设备文件
S_ISCHR测试是否是特殊的字符设备文件
S_ISDIR测试是否是目录
S_ISFIFO测试是否是FIFO
S_ISREG测试是否是普通文件
S_ISLNK测试是否是符号链接
dup和dup2系统调用
#include <unistd.h>
int dup(int fildes);
int dup2(int fildes, int fildes2);

dup复制文件描述符fildes,返回一个新的描述符。
dup2通过明确指定目标描述符来把一个文件描述符复制为另一个。

标准I/O库

在很多方面,使用标准I/O库的试和使用底层文件描述符一样。在标准I/O库中,与底层文件描述符对应的是流,它被实现为指向结构FILE的指针。

在启动程序时,有三个文件流是自动打开的:stdin、stdout和stderr,分别对应底层文件描述符的0、1和2。

fopen函数
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);

失败时返回NULL,NULL值在头文件stdio.h里定义。

参数mode取值说明
“r” 或 “rb”以只读方式打开
“w"或"wb”以写方式打开,并把文件长度截短为零
“a"或"ab”以写方式打开,新内容追加在文件尾
"r+"或"rb+“或"r+b”以更新方式打开(读和写)
"w+"或"wb+“或"w+b”以更新方式打开,并把文件长度截短为零
"a+"或"ab+“或"a+b”以更新方式打开,新内容追加在文件尾
fread函数
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);

数据从文件流stream读到ptr指向的数据缓冲区里,size表示每个数据记录的长度,nitems给出要传输的记录个数。

成功时返回成功读取的 记录个数(不是字节数)

fwrite函数
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream);

与fread类似。

fclose函数
#include <stdio.h>
int fclose(FILE *stream);

成功时返回0,否则返回EOF(-1)。

fflush函数
#include <stdio.h>
int fflush(FILE *stream);

把文件流中所有未写出的数据立刻写出。调用fclose函数隐含执行了一次flush操作。

fseek函数
#include <stdio.h>
int fseek(FILE *stream, long int offset, int whence);

与lseek系统调用完全一样,但返回的是一个整数:0表示成功,-1表示失败。

fgetc、getc和getchar函数
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar();

成功时返回下一个字节,失败(到达文件尾或出现错误,可以通过ferror或feof判断)时返回EOF。

getc作用和fgetc一样,但getc被实现为一个宏。

getchar相当于getc(stdin)。

fputc、putc和putchar函数
#include <stdio.h>
int fput(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

与fgetc、getc和getchar类似。

fgets和gets函数
#include <stdio.h>
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);

fgets不丢弃换行符,gets丢弃换行符。

fgets最多读取(n - 1)个字符,再加上’\0’。

gets没有长度限制,可能会溢出缓冲区,所以最好用fgets。

格式化输入和输出

printf、fprintf和sprintf函数
#include <stdio.h>
int printf(const char *format, ...);
int sprintf(char *s, const *format, ...);
int fprintf(FILE *stream, const char *format, ...);

printf相当于fprintf(stdout, const char *format, …)。

scanf、fscanf和sscanf函数
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);

与printf、fprintf和sprintf类似。

其他流函数
函数说明
fgetpos获得文件流的当前位置
fsetpos设置文件流的当前位置
ftell返回文件流当前位置的偏移值
rewind重置文件流的位置
freopen重新使用一个文件流
setvbut设置文件流的缓冲机制
remove相当于unlink函数但它的path参数是一个目录的话,其作用就相当于rmdir函数
文件流错误
#include <errno.h>
extern int errno;

函数调用失败时可以通过errno指出原因。

#include <stdio.h>
int ferror(FILE *stream);
int feof(FILE *stream);
void clearerr(FILE *stream);

前两者如果标识被设置则返回非零值,否则返回零。

clearerr可以清除错误标识,可以通过使用它从文件流的错误状态中恢复。例如,在“磁盘已满”错误解决之后,继续开始写入文件流。

文件流和文件描述符
#include <stdio.h>
int fileno(FILE *stream);
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);

更改所属。

unlink、link和symlink系统调用
#include <unistd.h>
int unlink(const char *path);
int link(const char *path1, const char *path2);
int symlink(const char *path1, const char path2);

unlink删除文件(链接数-1)。成功时返回0,失败时返回-1。

link系统调用将创建一个指向已有文件path1的新链接。新目录项由path2给出。

symlink与link类似,但创建的是符号链接。

mkdir和rmdir系统调用
#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);

创建目录。

#include <unistd.h>
int rmdir(const char *path);

删除目录(只能是空目录)。

chdir系统调用和getcwd函数
#include <unistd.h>
int chdir(const char *path);

切换目录。

#include <unistd.h>
char *getcwd(char *buf, size_t size);

把当前目录的名字写到给定的缓冲区buf里。如果目录名的长度超出了参数size(ERANGE错误)或程序运行过程中目录被删除(EINVAL错误)或有关权限发生了变化(EACCESS错误),它就返回NULL,如果成功就返回buf。

扫描目录

与目录操作有关的函数在 dirent.h 头文件中声明。

被称为目录流的指向这个结构的指针(DIR *)被用来完成各种操作,其使用方法与用来操作普通文件的文件流(FILE *)非常相似。

目录数据项本身则在dirent结构中返回,这是因为用户不应直接改动DIR结构中的数据字段。

opendir函数
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
readdir函数
#include <sys/types.h>
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
struct dirent 成员类型struct dirent 成员名称说明
ino_td_ino文件的inode节点号
char*d_name文件的名字

想要进一步了解目录中的某个文件,需要使用stat调用。

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);

设置目录流位置。

closedir函数
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

错误处理

错误代码和取值都在 errno.h 里定义。

错误代码说明
EPERM操作不允许
ENOENT文件或目录不存在
EINTR系统调用被中断
EIOIO错误
EBUSY设备或资源忙
EEXIST文件存在
EINVAL无效参数
EMFILE打开文件过多
ENODEV设备不存在
EISDIR是一个目录
ENOTDIR不是一个目录
strerror函数
#include <string.h>
char *strerror(int errnum);

把错误代码映射成字符串。

perror函数
#include <stdio.h>
void perror(const char *s);

把errno中的错误映射成字符串,并在前面加上s和": ",然后输出到标准错误输出流。

/proc文件系统

/proc中包含了许多特殊文件用来对驱动程序和内核信息进行更高层的访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值