📄 linux.txt
字号:
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name,struct stat *buf);
int fstat(int filedes,struct stat *buf);
struct stat {
dev_t st_dev; /* 设备 */
ino_t st_ino; /* 节点 */
mode_t st_mode; /* 模式 */
nlink_t st_nlink; /* 硬连接 */
uid_t st_uid; /* 用户ID */
gid_t st_gid; /* 组ID */
dev_t st_rdev; /* 设备类型 */
off_t st_off; /* 文件字节数 */
unsigned long st_blksize; /* 块大小 */
unsigned long st_blocks; /* 块数 */
time_t st_atime; /* 最后一次访问时间 */
time_t st_mtime; /* 最后一次修改时间 */
time_t st_ctime; /* 最后一次改变时间(指属性) */
};
stat 用来判断没有打开的文件,而fstat 用来判断打开的文件.我们使用最多的属性是st_
mode.通过着属性我们可以判断给定的文件是一个普通文件还是一个目录,连接等等.可以
使用下面几个宏来判断.
S_ISLNK(st_mode):是否是一个连接.S_ISREG 是否是一个常规文件.S_ISDIR 是否是一个
17
目录S_ISCHR 是否是一个字符设备.S_ISBLK 是否是一个块设备S_ISFIFO 是否 是一个
FIFO 文件.S_ISSOCK 是否是一个SOCKET 文件. 我们会在下面说明如何使用这几个宏
的.
3、目录文件的操作
在我们编写程序的时候,有时候会要得到我们当前的工作路径。C 库函数提供了get
cwd 来解决这个问题。
#include <unistd.h>
char *getcwd(char *buffer,size_t size);
我们提供一个size 大小的buffer,getcwd 会把我们当前的路径考到buffer 中.如果buffer
太小,函数会返回-1 和一个错误号.
Linux 提供了大量的目录操作函数,我们学习几个比较简单和常用的函数.
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char *path,mode_t mode);
DIR *opendir(const char *path);
struct dirent *readdir(DIR *dir);
void rewinddir(DIR *dir);
off_t telldir(DIR *dir);
void seekdir(DIR *dir,off_t off);
int closedir(DIR *dir);
struct dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[NAME_MAX+1]; /* 文件名称 */
mkdir 很容易就是我们创建一个目录,opendir 打开一个目录为以后读做准备.readdir 读一
个打开的目录.rewinddir 是用来重读目录的和我们学的rewind 函数一样.closedir 是关闭
一个目录.telldir 和seekdir 类似与ftee 和fseek 函数.
下面我们开发一个小程序,这个程序有一个参数.如果这个参数是一个文件名,我们输出这
个文件的大小和最后修改的时间,如果是一个目录我们输出这个目录下所有文件的大小和
修改时间.
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
18
static int get_file_size_time(const char *filename)
{
struct stat statbuf;
if(stat(filename,&statbuf)==-1)
{
printf("Get stat on %s Error:%s\n",
filename,strerror(errno));
return(-1);
}
if(S_ISDIR(statbuf.st_mode))return(1);
if(S_ISREG(statbuf.st_mode))
printf("%s size:%ld bytes\tmodified at %s",
filename,statbuf.st_size,ctime(&statbuf.st_mtime));
return(0);
}
int main(int argc,char **argv)
{
DIR *dirp;
struct dirent *direntp;
int stats;
if(argc!=2)
{
printf("Usage:%s filename\n\a",argv[0]);
exit(1);
}
if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))exit(1);
if((dirp=opendir(argv[1]))==NULL)
{
printf("Open Directory %s Error:%s\n",
argv[1],strerror(errno));
exit(1);
}
while((direntp=readdir(dirp))!=NULL)
if(get_file_size_time(direntp-<d_name)==-1)break;
closedir(dirp);
exit(1);
}
4、管道文件
Linux 提供了许多的过滤和重定向程序,比如more cat
等等.还提供了< > | <<等等重定向操作符.在这些过滤和重 定向程序当中,都用到了管
道这种特殊的文件.系统调用pipe 可以创建一个管道.
#include<unistd.h>
19
int pipe(int fildes[2]);
pipe 调用可以创建一个管道(通信缓冲区).当调用成功时,我们可以访问文件描述符fild
es[0],fildes[1].其中fildes[0]是用来读的文件描述符,而fildes[1]是用来写的文件描
述符.
在实际使用中我们是通过创建一个子进程,然后一个进程写,一个进程读来使用的.
关于进程通信的详细情况请查看进程通信
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFFER 255
int main(int argc,char **argv)
{
char buffer[BUFFER+1];
int fd[2];
if(argc!=2)
{
fprintf(stderr,"Usage:%s string\n\a",argv[0]);
exit(1);
}
if(pipe(fd)!=0)
{
fprintf(stderr,"Pipe Error:%s\n\a",strerror(errno));
exit(1);
}
if(fork()==0)
{
close(fd[0]);
printf("Child[%d] Write to pipe\n\a",getpid());
snprintf(buffer,BUFFER,"%s",argv[1]);
write(fd[1],buffer,strlen(buffer));
printf("Child[%d] Quit\n\a",getpid());
exit(0);
}
else
{
close(fd[1]);
printf("Parent[%d] Read from pipe\n\a",getpid());
memset(buffer,'\0',BUFFER+1);
20
read(fd[0],buffer,BUFFER);
printf("Parent[%d] Read:%s\n",getpid(),buffer);
exit(1);
}
}
为了实现重定向操作,我们需要调用另外一个函数dup2.
#include <unistd.h>
int dup2(int oldfd,int newfd);
dup2 将用oldfd 文件描述符来代替newfd 文件描述符,同时关闭newfd 文件描述符.也就
是说
,
所有向newfd 操作都转到oldfd 上面.下面我们学习一个例子,这个例子将标准输出重定向
到一个文件.
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFER_SIZE 1024
int main(int argc,char **argv)
{
int fd;
char buffer[BUFFER_SIZE];
if(argc!=2)
{
fprintf(stderr,"Usage:%s outfilename\n\a",argv[0]);
exit(1);
}
if((fd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==
-1)
{
fprintf(stderr,"Open %s Error:%s\n\a",argv[1],strerror(errno));
exit(1);
}
if(dup2(fd,STDOUT_FILENO)==-1)
{
fprintf(stderr,"Redirect Standard Out Error:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,"Now,please input string");
21
fprintf(stderr,"(To quit use CTRL+D)\n");
while(1)
{
fgets(buffer,BUFFER_SIZE,stdin);
if(feof(stdin))break;
write(STDOUT_FILENO,buffer,strlen(buffer));
}
exit(0);
}
好了,文件一章我们就暂时先讨论到这里,学习好了文件的操作我们其实已经可以写出一
些比较有用的程序了.我们可以编写一个实现例如dir,mkdir,cp,mv 等等常用的文件操作
命令了.
想不想自己写几个试一试呢?
四、时间的概念
1、时间表示
在程序当中,我们经常要输出系统当前的时间,比如我们使用date 命令的输出结果.这个
时候我们可以使用下面两个函数
#include <time.h>
time_t time(time_t *tloc);
char *ctime(const time_t *clock);
time 函数返回从1970 年1 月1 日0 点以来的秒数.存储在time_t 结构之中.不过这个
函数的返回值对于我们来说没有什么实际意义.这个时候我们使用第二个函数将秒数转化为
字符串.. 这个函数的返回类型是固定的:一个可能值为. Thu Dec 7 14:58:59 2000 这个
字符串的长度是固定的为26
2、时间的测量
有时候我们要计算程序执行的时间.比如我们要对算法进行时间分析..这个时候可以使
用下面这个函数.
#include <sys/time.h>
int gettimeofday(struct timeval *tv,struct timezone *tz);
strut timeval
{
long tv_sec; /* 秒数 */
long tv_usec; /* 微秒数 */
};
gettimeofday 将时间保存在结构tv 之中.tz 一般我们使用NULL 来代替.
#include <sys/time.h<
#include <stdio.h<
#include <math.h<
22
void function()
{
unsigned int i,j;
double y;
for(i=0;i<1000;i++)
for(j=0;j<1000;j++)
y=sin((double)i);
}
main()
{
struct timeval tpstart,tpend;
float timeuse;
gettimeofday(&tpstart,NULL);
function();
gettimeofday(&tpend,NULL);
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+
tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf("Used Time:%f\n",timeuse);
exit(0);
}
这个程序输出函数的执行时间,我们可以使用这个来进行系统性能的测试,或者是函数
算法的效率分析.在我机器上的一个输出结果是: Used Time:0.556070
3、计时器的使用
Linux 操作系统为每一个进程提供了3 个内部间隔计时器.ITIMER_REAL:减少实际时
间.到时的时候发出SIGALRM 信号.
ITIMER_VIRTUAL:减少有效时间(进程执行的时间).产生SIGVTALRM 信号.
ITIMER_PROF:减少进程的有效时间和系统时间(为进程调度用的时间).这个经常和上面
一个使用用来计算系统内核时间和用户时间.产生SIGPROF 信号.
具体的操作函数是:
#include <sys/time.h>
int getitimer(int which,struct itimerval *value);
int setitimer(int which,struct itimerval *newval,
struct itimerval *oldval);
struct itimerval
{
struct timeval it_interval;
struct timeval it_value;
}
getitimer 函数得到间隔计时器的时间值.保存在value 中 setitimer 函数设置间隔计时
器的时间值为newval.并将旧值保存在oldval 中. which 表示使用三个计时器中的哪一
个.itimerval 结构中的it_value 是减少的时间,当这个值为0 的时候就发出相应的信号了.
然后设置为it_interval 值.
23
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#define PROMPT "时间已经过去了两秒钟\n\a"
char *prompt=PROMPT;
unsigned int len;
void prompt_info(int signo)
{
write(STDERR_FILENO,prompt,len);
}
void init_sigaction(void)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -