1 lseek函数
函数:off_t lseek(int fd, off_t offset, int whence)
头文件:#include <unistd.h> #include <sys/types.h>
参数:fd 文件描述符
offset 偏移量,可以为正,也可以为负数
whence 偏移的起始位置,由三种可以设置
SEEK_SET #开头位置
The file offset is set to offset bytes.
SEEK_CUR #光标所在位置
The file offset is set to its current location plus offset bytes.
SEEK_END #文件结束位置
The file offset is set to the size of the file plus offset bytes.
返回值:正常结束,返回从头开始到偏移所在位置的字节数;如果发生错误,返回-1
特别的:当文件的偏移值超过其允许值时,文件会被拓展
注意:文件的读和写使用同一偏移位置
一个lseek函数的使用的demo:
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
int fd1;
int flag,i=0;
char s1[]="It's a lseek test\n";
char c;
fd1=open("lseek.txt",O_CREAT|O_RDWR,0664);
if(fd1<0){
perror("create file failed");
}
while((c=s1[i])!='\0'){
write(fd1,&c,1);
i++;
}
//此处写了三种插入位置的lseek()函数
//若此处不插入函数,再次读取字符时,会从上次写入位置的末尾进行读取
//结果就是什么都读取不到
lseek(fd1,0,SEEK_SET);
// lseek(fd1,-strlen(s1),SEEK_END);
// lseek(fd1,-strlen(s1),SEEK_CUR);
while((flag=read(fd1,&c,1))!=0){
write(STDOUT_FILENO,&c,1);
}
close(fd1);
return 0;
}
其它应用场景:
(1)使用lseek获取文件大小;
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int fd1;
int length=0;
fd1=open(argv[1],O_RDWR);
if(fd1<0){
perror("open file error");
}
length=lseek(fd1,0,SEEK_END);
printf("The size of file is %d\n",length);
close(fd1);
return 0;
}
(2)拓展文件大小;
使用lseek尾部向后偏移;
lseek(fd,N,SEEK_END); //N=偏移字节数-1;
write(fd,"\0",1);//真正引起文件大小改变,必须进行IO操作
od -tcx [file]
使用truncate()函数也可以拓展文件大小;
int ret=truncate(“dict.cp”,250);
2 传入参数和传出参数
传入参数:
1.指针作为函数参数;
2.通常由const关键字修饰;(因为是传入参数,使用const可以防止值被篡改)
3.指针指向有效区域,在函数内部做读操作;
例如:char *strcpy(char *dest, const char *src) 中的src
传出参数:
1.指针作为函数参数;
2.在函数调用之前,指针指向的空间可以无意义,但必须有效;
3.在函数内部,做写操作;
4.函数调用结束后,充当函数返回值;
例如:char *strcpy(char *dest, const char *src) 中的dest
传入传出参数:
1.指针作为函数参数;
2.在函数调用之前,指针指向的空间由实际意义;
3.在函数内部,先做读操作,在做写操作;
4.在函数调用结束后,可以充当函数的返回值;
例如:char *strtok_r(char *str,const char *delim, char ** saveptr)
3 文件系统和文件存储
inode:使用stat file 可以查看文件的inode
inode本质是结构体,存储文件的属性信息,如:权限,类型,大小,时间,用户,盘块位置…也叫作文件属性管理结构,大多数inode都存储在磁盘上
少量常用/近期使用的inode会被缓存到内存当中
dentry:目录项,其本质依然是结构体,重要成员变量由两个{文件名;inode;…},而文件内容(data)保存在磁盘盘块中;
删除文件不是把文件删除掉,而是用新文件覆盖旧文件;
磁盘格式化之后,仍然是可以做数据恢复的,但可以通过倒入大视频进去,重新写入文件,将原来的文件覆盖;
4 stat函数
**函数:int stat(const char path, struct stat buf)
头文件:#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
参数:path 文件路径
buf 传出参数,
返回值:成功返回0,失败返回-1;
功能描述:These functions return information about a file, in the buffer pointed to by statbuf. No permissions are required on the file itself, but—in the case of stat(), fstatat(), and lstat()—execute (search) permission is required on all of the directories in pathname that lead to the file.
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
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; /* Block size 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
};
属性:st_mode
stat穿透,在使用stat查看一个文件的软连接有关信息时,发现得到的信息时源文件的信息,而不是软链接的信息,这种现象叫做stat穿透。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
struct stat sbuf;
int ret=stat(argv[1],&sbuf);
if(ret==-1){
perror("open file error!");
exit(-1);
}
printf("The size of file is %ld\n",sbuf.st_size);
if(S_ISREG(sbuf.st_mode)){
printf("this is a regular file!\n");
}
else if(S_ISDIR(sbuf.st_mode)){
printf("this is dir\n");
}
else if(S_ISLNK(sbuf.st_mode)){
printf("this is soft link\n");
}
else{
printf("the file is unknown");
}
return 0;
}
-rwxrwxr-x 1 daniel daniel 16792 5月 11 03:41 block
lrwxrwxrwx 1 daniel daniel 7 5月 11 14:09 block1 -> block.c
daniel@daniel-Vostro-5471:~/文档/OS/test/IO_test$ ./stat.out block1
The size of file is 217
this is a regular file!#显示的是软链接的源文件的信息
stat函数和lstat函数基本相同,不同之处在于stat会穿透符号连接,而lstat函数不会穿透符号连接;
将上面的stat函数修改为lstat函数,发现不再穿透符号连接。
daniel@daniel-Vostro-5471:~/文档/OS/test/IO_test$ ./stat.out block1
The size of file is 7
this is soft link
S_IFMT 0170000 bit mask for the file type bit field
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
Thus, to test for a regular file (for example), one could write:
stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {
/* Handle regular file */
}
使用stat.st_mode判断文件类型的相关帮助位于: man 7 inode
5 其它简单函数
acess chmod truncate
*函数:int access(const char pathname,int mode);
头文件:#include <fcntl.h> #include <unistd.h>
功能:
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, respectively.
参数:pathname 填入检测文件的路径
mode 添加检测文件的权限
返回值:
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 ap propriately.
demo:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char** argv)
{
int ret1=access(argv[1],F_OK);
if(ret1==-1){
perror("can't find the file\n");
}
else{
printf("The file is exit!\n");
}
int ret2=access(argv[1],R_OK);
if(ret2==-1){
perror("can't read the file!\n");
}
else{
printf("you can read the file\n");
}
return 0;
}
*函数:int chmod(const char pathname,mode_t mode)
头文件:#include <sys/stat.h>
功能:更改文件的属性
参数:pathname是文件的地址,mode是一系列代表文件属性的宏定义,具体可查看帮助文档 man 2 chmod
返回值: On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
*函数:int truncate(const char path,off_t length)
int ftruncate(int fd, off_t length)
头文件:#include <unistd.h> #include<sys/types.h>
功能:
The truncate() and ftruncate() functions cause the regular file named by path or referenced by fd to be truncated to a size of precisely length bytes. If the file previously was larger than this size, the extra data is lost.
If the file previously was shorter, it is extended, and the extended part reads as null bytes ('\0').
The file offset is not changed. If the size changed, then the st_ctime and st_mtime fields (respectively, time of last status change and time of last modification; see inode(7)) for the file are updated, and the set-user-ID and set-group-ID mode bits may be cleared.
With ftruncate(), the file must be open for writing; with truncate(), the file must be writable.
参数:path文件路径 fd 文件描述符 length 截断字节数
返回值:
成功返回0,失败返回-1;
demo:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main(int argc, char** argv)
{
int ret=truncate(argv[1],10);
if(ret==-1){
perror("can't truncate the file!\n");
}
else{
printf("truncate the file successfully!\n");
}
return 0;
}
6 link/ulink/隐式回收
**函数:int link(const char oldpath, const char newpath);
头文件:#include <unistd.h>
功能:创建硬连接
之前文件存储的dentry是一个由文件名和inode组成的结构体,使用硬连创建的文件只是文件名不同,inode完全相同,即在磁盘上指向同一片区域,修改一个文件,另外一个也会修改
参数:oldpath 旧文件路径 newpath 新文件路径
返回值:成功,返回0,失败,返回-1
*函数:int unlink(const char pathname)
头文件:#include <unistd.h>
功能:删除文件的目录项。linux中删除文件是不断将st_link减1,直到st_link为0为止。无目录对应项的文件会被操作系统择机释放掉。
unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse.
If the name was the last link to a file but any processes still have the file open, the file will remain in existence until the last file descrip tor referring to it is closed.
If the name referred to a symbolic link, the link is removed.If the name referred to a socket, FIFO, or device, the name for it is removed but processes which have the object open may continue to use it.
参数:pathname 文件路径
返回值:成功,返回0 失败,返回-1
实现shell中mv功能的demo:
#include <unistd.h>
#include <stdio.h>
int main (int argc, char** argv){
if(argc!=3){
printf("the num of argv is wrong!\n");
}
int ret=link(argv[1],argv[2]);
if(ret==-1){
perror("move error!\n");
}
else{
int ret2=unlink(argv[1]);
if (ret2==-1){
perror("delete the oldfile error!\n");
}
}
return 0;
}
unlink函数的特征,清除文件时,硬连接数到0了,没有dentry对应,但是该文件不会被马上释放掉,要等到所有打开该文件的进程关闭这个文件,系统才会挑时间将文件释放。一个demo代码:
//创建一个temp临时文件,并在程序结束后删除
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
int fd;
int ret;
char* str1="this is the test1\n";
char* str2="this is the test2\n";
fd=open("temp.txt",O_RDWR|O_CREAT,0664);
//>>1
if(fd==-1){
perror("can't create the file!");
exit(-1);
}
ret=write(fd,str1,strlen(str1));
if(ret==-1){
perror("write failed!");
exit(-1);
}
printf("write test1 successfully!\n");
ret=write(fd,str2,strlen(str2));
if(ret==-1){
perror("write failed!");
exit(-1);
}
printf("write test2 successfully!press enter to continue!\n");
//使用getchar()接收一个回车,当回车没有按下时,temp.txt文件存在
//当回车按下,调用unlink函数,进程接收,temp.txt被删除
getchar();
close(fd);
//将下句移动1处,依然可以执行写操作,并且不报错
ret=unlink("temp.txt");
if(ret==-1){
perror("unlink the file failed!\n");
exit(-1);
}
return 0;
}
隐式回收:当进程结束运行时,所有进程打开的文件会被关闭,申请的内存空间将被释放,系统这一特性称为隐式回收系统资源;
7 文件目录和rwx权限差异
readlink softlink 可以查看软连接的内容
daniel@daniel-Vostro-5471:~/文档/OS/test/IO_test$ readlink 1
/home/daniel/文档/OS/test/IO_test/1.txt
int rename(const char* oldpath, const char* newpath)
给文件重命名,成功返回0,失败返回-1