【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

时间:2022-06-08 17:55:06

  最近学习linux系统下的应用编程,参考书籍是那本称为神书的《Unix环境高级编程》,个人感觉神书不是写给草鞋看的,而是

写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻的感觉。我自己就是这样,比方说看进程间通信信号量章

节的时候,开始感觉就很迷糊,因此也就想在这里写一些文字,给和我一样的草鞋分享一些自己的学习经历(算不上经验吧)。

  环境:   windows7,  VMware  9.0   

  操作系统版本: RHEL  5.5  

    内核版本:  2.6.18-194.el5 

  Gcc版本:    gcc 版本 4.1.2 20080704 (Red Hat 4.1.2-48)   【2008年7月4日构建的】

  【linux草鞋应用编程系列】的系列文章,欢迎批评指正。 欢迎转载,如果您愿意可以添加本系列文章的链接,即本草鞋的在博客园

的链接。

  正文中的函数的原型都是通过  man page 查看和复制到,查看的时候如果与这里的不一样,请以查看的为准, 因为不同的内核

版本支持的函数,以及函数的参数可能存在一些出入。

  废话少说,下面开始正题。

  开篇:  系统调用IO接口与标准IO接口

正文:

一、系统IO     linux系统下面提供了一套系统API来实现外设的IO操作。   1、文件的打开     系统调用open( )用于打开文件,其函数原型如下所示:
NAME
open, creat
- open and possibly create a file or device

SYNOPSIS
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<fcntl.h>

int open(const char *pathname, //要打开的文件的路径和文件名
int flags); //打开方式


int open(const char *pathname, //要打开的文件的路径和文件名
int flags, //打开方式 , 这个格式的调用,表示使用了 O_CREAT 打开方式标志。
mode_t mode); //打开后文件的权限

int creat(const char *pathname, //要创建的文件的路径和文件名
mode_t mode); //创建后文件的权限
    open: 打开或者创建一个文件。                 参数flags :  如果有 O_CREAT 标志,则表示如果文件存在直接打开,否则就创建新文件; mode表示创建的 文件的读、写、执行 权限, 用 8 进制指定。
 mode must be specified when O_CREAT is in the flags, and is ignored otherwise.
creat()
is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.
  open使用O_CREAT标志的时候,使用第二种调用形式,必须设置mode参数;   creat() 函数相当于调用open 且给第二个参数传递   O_CREAT|O_WRONLY|O_TRUNC.  三个标志的按位或结果
    返回值:             成功返回文件描述符,失败返回 -1.     要点:             O_RDONLY、O_WRONLY、O_RDWR 三个标志必须取其中一个,而且三个标志互斥(即 取一个且只能取一个)     这三个标志用于open的第二个参数   2、文件的读     系统用 read 进行文件的读
NAME
read
- read from a file descriptor

SYNOPSIS
#include
<unistd.h>

ssize_t read(
int fd, //要读取文件的文件描述符
void *buf, //读取数据存储的缓冲区
size_t count); //要读取字节数

    返回值:

                    成功返回读取的字节数,  返回0 表示道文件结尾。                     失败返回-1。   3、 文件的写       用 write 函数进行文件的写入。
NAME
write
- write to a file descriptor

SYNOPSIS
#include
<unistd.h>

ssize_t write(
int fd, //要写入文件的文件描述符
const void *buf, //待写入数据的缓冲区
size_t count); //要写入的字节数
  返回值:
成功返回写入到字节数, 返回0 表示没有写入任何东西。
失败返回
- 1 .
  简单的文件复制程序:
#include <stdio.h>
#include
<fcntl.h>
#include
<unistd.h>
#include
<string.h>
#include
<stdlib.h>

#define BUF_LEN 1024

int main(int argc, char* argv[])
{
int fd_src,
fd_dst;
char buf[BUF_LEN];
int ret;
int ret_r;

if(argc < 3)
{
printf(
"usage: cpfile file_src file_dst\n");
printf(
"\tfile_src:file want to copy\n");
printf(
"\tfile_dst:file where to store\n");
exit(
0);
}

fd_src
=open(argv[1], O_RDONLY);
if(-1 == fd_src )
{
strcpy(buf,
"open ");
strcat(buf,argv[
1]);
perror(buf);
exit(
1);
}
fd_dst
=open(argv[2],O_WRONLY|O_CREAT,00666);
if(-1 == fd_dst )
{
strcpy(buf,
"open ");
strcat(buf,argv[
2]);
perror(buf);
exit(
1);
}

do
{
memset(buf,
0,sizeof(buf));
ret_r
=read(fd_src,buf,sizeof(buf) );
if(-1 == ret)
{
strcpy(buf,
"read ");
strcat(buf,argv[
1]);
perror(buf);
exit(
2);
}
ret
=write(fd_dst,buf,ret_r);
if(-1 == ret)
{
strcpy(buf,
"write ");
strcat(buf,argv[
2]);
perror(buf);
exit(
3);
}
}
while( ret_r != 0);

close(fd_src);
close(fd_dst);
return 0;
}

 

4、目录操作     要对目录进行操作需要先打开目录,用 opendir 打开目录。
NAME
opendir
- open a directory

SYNOPSIS
#include
<sys/types.h>
#include
<dirent.h>

DIR
*opendir(const char *name); //要打开的目录的路径和目录名
    数据类型:              DIR类型表示指向打开目录的指针,通过这个指针对目录进行操作。     返回值:             成功返回指向打开目录的指针,失败返回NULL。   5、获取目录下的文件项     通过 readdir 来获取目录下的目录项。 readdir 分为系统调用readdir, 以及库函数readdir, 通常使用 库函数readdir。
READDIR(3)                 Linux Programmer’s Manual                READDIR(3)
NAME
readdir
- read a directory
SYNOPSIS
#include
<sys/types.h>
#include
<dirent.h>

struct dirent *readdir(DIR *dir); //要读取的目录的指针
    返回值:             成功返回一个描述目录项的指针, 当读取到最后一个目录项的时候返回NULL, 失败也返回NULL,           目录项指针是一个数据结构体类型: struct  dirent 其定义如下:
       struct dirent {
ino_t d_ino;
/* inode number */
off_t d_off;
/* offset to the next dirent */
unsigned
short d_reclen; /* length of this record */
unsigned
char d_type; /* type of file */ //文件类型
char d_name[256]; /* filename */ //文件名
};

 

  下面一个简单的目录操作程序: 实现 ls 的功能
#include <stdio.h>
#include
<unistd.h>
#include
<dirent.h>
#include
<stdlib.h>

int main(int argc, char* argv[])
{
DIR
*dir=NULL;
struct dirent *file=NULL;

if(argc < 2) //如果没有指定要显示的目录,就显示当前目录的的文件
{
dir
=opendir("./");
if(!dir)
{
perror(
"open");
exit(
1);
}
else
{
while(file=readdir(dir))
printf(
"%s\t",file->d_name);
}
putchar(
'\n');
closedir(dir);
exit(
0);
}

dir
=opendir(argv[1]);
if(!dir)
{
perror(
"open");
exit(
1);
}
while(file=readdir(dir))
printf(
"%s",file->d_name);

printf(
"\n");
closedir(dir);
return 0;
}
执行结果如下:
[root@localhost ls]# ls
main.c
[root@localhost ls]# gcc
-o dir main.c
[root@localhost ls]# .
/dir
dir main.c .. .
[root@localhost ls]#

 

6、查看某个文件是否存在    有时需要检测某个文件是否存在。 例如复制文件的时候,既需要检测文件是否存在,存在的话就需要提醒用户是否需要覆盖。    通过  access( ) 来检测文件是否存在、是否可写等信息。
ACCESS(2)                  Linux Programmer’s Manual                 ACCESS(2)
NAME
access
- check user’s permissions for a file
SYNOPSIS
#include
<unistd.h>

int access( const char *pathname, //要检查的文件路径和文件名
int mode); //要检测的内容,如文件是否存在 F_OK 等
修改后的 cpfile.c 如下
#include <stdio.h>
#include
<fcntl.h>
#include
<unistd.h>
#include
<string.h>
#include
<stdlib.h>

#define BUF_LEN 1024

int main(int argc, char* argv[])
{
int fd_src,
fd_dst;
char buf[BUF_LEN];
int ret;
int ret_r;

if(argc < 3) //参数小于3个,就打印提示信息
{
printf(
"usage: cpfile file_src file_dst\n");
printf(
"\tfile_src:which file want to copy\n");
printf(
"\tfile_dst:file where to store\n");
printf(
"\n\tIf the file_src and file_dst without path,"
"will operation at current directory\n");
exit(
0);
}

//检测目标文件是否存在
if( ! access(argv[2],F_OK) )
{
printf(
"%s exist,do you want to overwrite it?(y/n):",argv[2]);
buf[
0]=getchar();
if( 'n' == buf[0] )
exit(
0);
}

fd_src
=open(argv[1], O_RDONLY);
if(-1 == fd_src )
{
strcpy(buf,
"open ");
strcat(buf,argv[
1]);
perror(buf);
exit(
1);
}
fd_dst
=open(argv[2],O_WRONLY|O_CREAT,00666);
if(-1 == fd_dst )
{
strcpy(buf,
"open ");
strcat(buf,argv[
2]);
perror(buf);
exit(
1);
}

do
{
memset(buf,
0,sizeof(buf));
ret_r
=read(fd_src,buf,sizeof(buf) );
if(-1 == ret)
{
strcpy(buf,
"read ");
strcat(buf,argv[
1]);
perror(buf);
exit(
2);
}
ret
=write(fd_dst,buf,ret_r);
if(-1 == ret)
{
strcpy(buf,
"write ");
strcat(buf,argv[
2]);
perror(buf);
exit(
3);
}
}
while( ret_r != 0);

close(fd_src);
close(fd_dst);
return 0;
}

 

 7、获取文件的属性    linux中文件具有各种属性,有时需要获取这些文件的信息,例如 ls -l 命令会显示目录下文件的信息。在linux中可以通过 stat、fstat、lstat 函数获取文件的相关信息。
STAT(2)                    Linux Programmer’s Manual                   STAT(2)
NAME
stat, fstat, lstat
- get file status
SYNOPSIS
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<unistd.h>

int stat(const char *path, //要查看的文件的路径和文件名
struct stat *buf); //输出参数, 用于存储文件信息的结构体指针

int fstat(int filedes, //打开的文件的文件描述符
struct stat *buf); //输出参数, 用于存储文件信息的结构体指针

int lstat(const char *path, //要查看的文件的路径和文件名
struct stat *buf); //输出参数, 用于存储文件信息的结构体指针

返回值:    

            成功返回0, 失败返回 -1 ; 结构体:
        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 */ //用户ID
gid_t st_gid; /* group ID of owner */ //组ID
dev_t st_rdev; /* device ID (if special file) */ //特殊文件ID号
off_t st_size; /* total size, in bytes */ //文件大小
blksize_t st_blksize; /* blocksize for filesystem I/O */ //文件IO的块大小
blkcnt_t st_blocks; /* number of blocks allocated */ //文件使用的块数目
time_t st_atime; /* time of last access */ //最后访问时间
time_t st_mtime; /* time of last modification */ //最后修改时间
time_t st_ctime; /* time of last status change */ //最后
};
    下面为为改进后的简易 ls 命令源代码: 可以显示更多的信息
#include <stdio.h>
#include
<unistd.h>
#include
<dirent.h>
#include
<stdlib.h>
#include
<sys/stat.h>
#include
<string.h>

#define BUF_SIZE 512

//定义一个函数解析文件信息
void show_stat(char buf[] ,struct stat f_stat)
{
printf(
"File : %s\n",buf);
printf(
"\tuser id: %d\n", f_stat.st_uid);
printf(
"\tgroup id: %d\n",f_stat.st_gid);
printf(
"\tfile size:%.3fK\n", 1. * f_stat.st_size /1024); //显示3位小数
printf("\tfile ulink:%d\n",f_stat.st_nlink);
}

//定义一个函数遍历目录
void dir(const char *path)
{
DIR
*dir=NULL; //打开的目录
struct dirent *f_dir=NULL; //存储目录项
char buf[1024]={};
struct stat f_stat={}; //用来检测文件的信息
int ret=0;

//打开目录
dir=opendir(path);
if(!dir)
{
strcpy(buf,
"acces directory:");
strcat(buf,path);
perror(buf);
exit(
1);
}

//遍历目录
while( f_dir = readdir(dir) )
{
//首先获取文件的路径和文件名
strcpy(buf,path); //路径
strcat(buf,"/"); //添加路径分割符号
strcat(buf,f_dir->d_name); //文件名,buf包含路径名和文件名

//获取目录项的属性
ret=stat(buf,&f_stat);
if(ret)
{
perror(buf);
}

if(S_ISDIR(f_stat.st_mode)) //如果是目录
{
printf(
"File : %s\n",f_dir->d_name);
printf(
"\tA directory\n");
}
else if(S_ISREG(f_stat.st_mode))
{
show_stat(f_dir
->d_name, f_stat);
}
else
{
printf(
"File : %s\n", f_dir->d_name);
printf(
"\tother file type");
}
}
//遍历目录结束
}

int main(int argc, char* argv[])
{
struct stat f_stat;
int ret;
char buf[BUF_SIZE];

//首先判断是否有第二个参数, 没有就显示当前目录
if( argc < 2 )
{
dir(
"."); //注意这个地方,不能传递"./",因为dir函数中会添加最后一个反斜杠
exit(0); //显示完成就退出
}

//有第二个参数
ret=stat(argv[1],&f_stat);
if(ret)
{
strcpy(buf,
"access ");
strcat(buf,argv[
1]);
perror(buf);
exit(
1);
}
if(S_ISDIR(f_stat.st_mode)) //如果是目录
{
dir(argv[
1]);
}
if(S_ISREG(f_stat.st_mode)) //如果是文件
{
show_stat(argv[
1],f_stat);
}
return 0;
}
 8、改变工作目录    应用程序执行的时候,都有一个工作目录:当前目录, 有时候需要在程序执行的时候切换当前目录到其他目录。    在程序中,可以通过函数改变 当前工作目录:    chdir( )
CHDIR(2)                   Linux Programmer’s Manual                  CHDIR(2)
NAME
chdir, fchdir
- change working directory
SYNOPSIS
#include
<unistd.h>

int chdir(const char *path); //要切换到的工作目录
int fchdir(int fd); //通过打开的文件描述符,切换到打开的文件所在的目录
    返回值:            成功返回0, 失败返回-1 。 9、获取当前工作目录    在应用程序中,有时可能会多次改变工作目录,为了跟踪应用程序的当前工作目录,可以通过函数 getcwd ( ) 来获取当前的工作目录。
GETCWD(3)                  Linux Programmer’s Manual                 GETCWD(3)
NAME
getcwd, get_current_dir_name, getwd
- Get current working directory

SYNOPSIS
#include
<unistd.h>

char *getcwd( char *buf, //输出函数,用来存储当前路径的缓存区域
size_t size); //缓存区域的大小
返回值:        成功返回 buf, 失败返回NULL, 同时设置全局变量 error;        如果路径大于buf的大小,那么 errno 将被设置为  ERANGE Exp:  chdir.c
#include <stdio.h>
#include
<unistd.h>
#include
<stdlib.h>
#include
<errno.h> //访问错误值代码

extern int errno;
int main(void)
{
char* buf=NULL;
int ret;

buf
=(char *)malloc(1024);

buf
=getcwd(buf,1024);
if(!buf)
{
if(ERANGE == errno)
buf
=(char *)realloc(buf,2048);
}
buf
=getcwd(buf,2048);
printf(
"before change directroy: %s\n\n",buf);

ret
=chdir("/home/volcanol");
if(ret)
{
perror(
"/home/volcanol");
exit(
1);
}
buf
=getcwd(buf,2048);
printf(
"after change directory:%s\n\n",buf);

free(buf);
return 0;
}
  二、标准库IO:  <stdio.h>    标准库IO的特点是:  调用系统API接口实现标准库IO。标准库IO函数都是具有缓冲机制的IO接口。 1、printf      printf 在输出时先将数据写入到缓冲区域,在遇到 '\n' 字符的时候才将数据从缓冲区显示到标准输出设备。Exp:
#include <stdio.h>
#include
<unistd.h> //to use sleep()

int main(void)
{
int i=0;

for(i=0;i<5;i++)
{
printf(
"%d ",i);
sleep(
1); //为了查看效果,才加上sleep();
}

printf(
"\n");

return 0;
}

  执行的时候,可以看到 0、1、2、3、4 不是一个一个的输出,而是一起输出的。

     printf也会在缓冲区满的时候,输出数据。    为了查看缓冲区满的时候printf函数输出数据,可以对缓冲区进行设置, 通过函数 setvbuf 设置缓冲的大小和缓冲模式。        标准输出的缓冲机制有三种:            A:  无缓冲            B:   行缓冲            C:   全缓冲        setvbuf( )的原型为:
SETBUF(3)                  Linux Programmer’s Manual                 SETBUF(3)
NAME
setbuf, setbuffer, setlinebuf, setvbuf
- stream buffering operations
SYNOPSIS
#include
<stdio.h>

void setbuf(FILE *stream,
char *buf);

void setbuffer(FILE *stream,
char *buf,
size_t size);

void setlinebuf(FILE *stream); //设置为行缓冲, stream 表示设置缓冲的文件

int setvbuf(FILE *stream, //要缓冲的文件,标准输出为 stdout
char *buf, //缓冲区的首地址, =NULL 表示系统分配,
int mode , //缓冲模式,行缓冲、全缓冲、无缓冲
size_t size); //缓冲区大小
    mode 的取值由下面的宏指定:               _IONBF unbuffered     :  无缓冲              _IOLBF line buffered     : 行缓冲              _IOFBF fully buffered    :全缓冲, 主要用于 文件。      其他三个函数都是调用 setvbuf 实现的,因此了解 setvbuf, 就能知道其他函数的用法。    返回值:            成功返回0 ;失败返回任意值,会设置errno。 Exp:  setvbuf.c    第一次设置为: 无缓冲模式
#include <stdio.h>
#include
<unistd.h> //to use sleep()

int main(void)
{
int i=0;

setvbuf( stdout, NULL , _IONBF ,
0 );

for(i=0;i<5;i++)
{
printf(
"%d ",i);
sleep(
1); //为了查看效果,才加上sleep();
}

printf(
"\n");
return 0;
}

  程序执行的过程中: 可以看到数字一个一个的输出,而不是一起输出。

Exp: 第二次设置为缓冲区大小为1个字节,测试缓冲区满就输出
#include <stdio.h>
#include
<unistd.h> //to use sleep()

int main(void)
{
int i=0;
char buf[1]={};

/*setvbuf(stdout, NULL, _IONBF ,0);*/
setvbuf(stdout, buf , _IOLBF ,
1);

for(i=0;i<5;i++)
{
printf(
"%d ",i);
sleep(
1); //为了查看效果,才加上sleep();
}

printf(
"\n");
return 0;
}

  可以看到数组0、1、2、3、4是一个一个的输出,而不是一起输出。

     还可以调用函数  fflush 来将数据从输出从缓冲区刷出,从而 printf 可以不必在遇到 '\n' 或者缓冲满的时候
#include <stdio.h>
#include
<unistd.h> //to use sleep()

int main(void)
{
int i=0;
char buf[1]={};

/*setvbuf(stdout, NULL, _IONBF ,0);*/
/*setvbuf(stdout, buf , _IOLBF , 1);*/

for(i=0;i<5;i++)
{
printf(
"%d ",i);
fflush(stdout);
sleep(
1); //为了查看效果,才加上sleep();
}

printf(
"\n");
return 0;
}
特殊点:  printf("%s");输出结果为 (null)
[root@localhost cpfile]# ./a.out main.c cpfile.c 
(null) exist,do you want to overwrite it?(y/n):n
 2、scanf       scanf 在遇到 '\n' 时才能将数据从输入缓冲区读入。Exp:  scanf.c
#include <stdio.h>

int main(void)
{
char ch;
char ch_1;
char buf[32];
char buf_1[32];

scanf(
"%c%s",&ch,buf);
printf(
"c=%c, str=%s\n",ch,buf);

scanf(
"%c%s",&ch_1,buf_1);
printf(
"c=%c, str=%s\n",ch_1,buf_1);
return 0;
}
执行结果如下:
[root@localhost stdio]# vim scanf.c 
[root@localhost stdio]# gcc scanf.c
[root@localhost stdio]# .
/a.out
hello world
//输入 hello world 然后按下回车键
c=h, str=ello
c
= , str=world
    从这个地方可以知道:        scanf 函数在检测到输入 '\n' 后将数据写入到输入缓冲区; 而下一次调用的时候,会先检测缓冲区有没有数据,如果缓冲区有数据,则直接从缓冲区域里面读取数据。         %c 可以读取空白字符, %s会以空白符号表示字符串读取结束,且不会将空白符从缓冲区删除。                与输出的printf不一样,不能通过fflush将输入数据缓冲区的数据刷出。Exp:   
#include <stdio.h>

int main(void)
{
char ch;
char ch_1;
char buf[32];
char buf_1[32];

scanf(
"%c%s",&ch,buf);
printf(
"c=%c, str=%s\n",ch,buf);

fflush(stdin);
scanf(
"%c%s",&ch_1,buf_1);
printf(
"c=%c, str=%s\n",ch_1,buf_1);
return 0;
}
执行结果如下:[root@localhost stdio]# gcc scanf.c 
[root@localhost stdio]# ./a.out 
hello wolrd
c=h, str=ello
c= , str=wolrd      //输出结果为没有将输入数据缓冲区刷出
 3、其他IO输出函数    puts( ) : 不具有缓冲效果,直接输出, 即不会等到遇到 '\n' 时才输出数据。     gets(  ): 默认为行缓冲的输入。一次读入一行数据。    getch( );    putch( ); 4、标准输入的文件操作函数1) fopen    用于打开一个文件,返回指向文件的文件流指针。原型如下:
FOPEN(3)                   Linux Programmer’s Manual                  FOPEN(3)
NAME
fopen, fdopen, freopen
- stream open functions

SYNOPSIS
#include
<stdio.h>

FILE
*fopen(const char *path, //要打开的文件
const char *mode); //打开模式

FILE
*fdopen(int fildes, //已经用 open打开的文件的文件描述符
const char *mode); //打开模式,必须与open的模式兼容

// 下面的函数,将 stream 文件流重定向到 重新为 path 打开的文件流
FILE *freopen(const char *path,
const char *mode,
FILE
*stream);
2) fclose    fclose 用于关闭一个打开的文件流。
FCLOSE(3)                  Linux Programmer’s Manual                 FCLOSE(3)
NAME
fclose
- close a stream
SYNOPSIS
#include
<stdio.h>

int fclose(FILE *fp);
3) fread、fwrite    fread用于从文件流中读取数据。fwrite用于将数据写入到文件流。
FREAD(3)                   Linux Programmer’s Manual                  FREAD(3)
NAME
fread, fwrite
- binary stream input/output
SYNOPSIS
#include
<stdio.h>

size_t fread(
void *ptr, //存储读入数据的数据缓冲区首地址、指针
size_t size, //要读取的数据块的带小
size_t nmemb, //每次读取多少个数据块
FILE *stream); //要读取的文件流

size_t fwrite(
const void *ptr, //存储待写入数据的数据缓冲区首地址、指针
size_t size, //要写入到数据块的大小
size_t nmemb, //每次要写入多少个数据块
FILE *stream); //要写入的文件流
     读取时候,需要检测是否已经到文件尾,如果到文件尾,那么需要结束读取操作,或者进行重新定位。    A:  feof
FERROR(3)                  Linux Programmer’s Manual                 FERROR(3)
NAME
clearerr, feof, ferror, fileno
- check and reset stream status
SYNOPSIS
#include
<stdio.h>

void clearerr(FILE *stream);
int feof(FILE *stream); //检测是否到文件尾
int ferror(FILE *stream);
int fileno(FILE *stream);
    当检测到文件尾的时候,feof 返回非零值。          B: fseek
FSEEK(3)                   Linux Programmer’s Manual                  FSEEK(3)
NAME
fgetpos, fseek, fsetpos, ftell, rewind
- reposition a stream
SYNOPSIS
#include
<stdio.h>

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
int fgetpos(FILE *stream, fpos_t *pos);
int fsetpos(FILE *stream, fpos_t *pos);
利用标准输入实现文件复制程序:  cpfile.c 
#include <stdio.h>
#include
<stdlib.h>
#include
<string.h>

#define BUF_SIZE 512

int main(int argc, char* argv[])
{
char buf[BUF_SIZE]={};
FILE
* fp_src;
FILE
* fp_dst;

if(argc<3)
{
printf(
"usage: cpfile file_src file_dst\n");
puts(
"\t file_src: the source file");
puts(
"\t file_dst: the target file");
exit(
0);
}


fp_src
= fopen( argv[1], "r");
fp_dst
= fopen( argv[2], "w");

while( !feof(fp_src) )
{
memset(buf,
0, sizeof(buf));
fread(buf, BUF_SIZE,
1, fp_src);
fwrite(buf, BUF_SIZE,
1, fp_dst);
}

fclose(fp_src);
fclose(fp_dst);
return 0;
}

  执行的时候,可以成功复制文件。

   这是本系列的第一篇,系列文章未完待续。