Linux下文件的操作
8 {; t. ?/ m c9 f/ w4 z( H# I0 U前言:
2 d5 q' u) r/ E0 e, e7 Y我们在这一节将要讨论linux下文件操作的各个函数.
+ B6 E' G5 i. g! u: d% _/ d- Z2 N文件的创建和读写
3 L8 C0 p6 `0 k
文件的各个属性
- |/ S7 a! |% {+ ^4 O目录文件的操作
- M3 B) k/ j: O* @4 ]9 Q5 K- Z8 s管道文件
5 s; S1 u3 i# p% `
--------------------------------------------------------------------------------
+ i+ ^$ ^$ M5 W) Z1。文件的创建和读写
9 z+ F8 Y! u! P5 U! M
我假设你已经知道了标准级的文件操作的各个函数(fopen,fread,fwrite等等).当然如果你不清楚的话也不要着急.我们讨论的系统级的文件操作实际上是为标准级文件操作服务的.
1 I+ |, w; F( G0 [/ j- x# ~# B
当我们需要打开一个文件进行读写操作的时候,我们可以使用系统调用函数open.使用完成以后我们调用另外一个close函数进行关闭操作.
/ m: C% }+ ^% h$ v' [" l#include <fcntl.h>
. u" W' i$ Q2 K+ j' x6 y8 n#include <unistd.h>
% D" I1 q: Y! o* l5 L#include <sys/types.h>
+ L( {, p) C5 N( R0 ~#include <sys/stat.h>
% W: A5 Y( c" a
. c% l+ C& w) [- a4 Rint open(const char *pathname,int flags);
' I& b1 l, i1 s1 i" i1 N: o" Sint open(const char *pathname,int flags,mode_t mode);
# F7 ?9 L( y: U6 M h8 S4 l* G
int close(int fd);
2 X' ]$ ]& J5 h0 w& F3 ^+ U) e9 @open函数有两个形式.其中pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面).flags可以去下面的一个值或者是几个值的组合.
- A- W; j# a9 A$ K! t! h2 x4 Y, z
O_RDONLY:以只读的方式打开文件.
/ W" s* |3 Y9 m, z
O_WRONLY:以只写的方式打开文件.
/ \1 ^6 e8 L$ }6 e AO_RDWR:以读写的方式打开文件.
0 ~1 H, U& `/ | ]5 t+ `O_APPEND:以追加的方式打开文件.
. G4 _3 [+ Z+ {3 w+ t8 Z8 a- YO_CREAT:创建一个文件.
! e( f2 Q2 k% v. T# n5 cO_EXEC:如果使用了O_CREAT而且文件已经存在,就会发生一个错误.
& [7 u1 R9 a" A" F. v4 |/ s! m K0 W# U
O_NOBLOCK:以非阻塞的方式打开一个文件.
4 x3 F- C# {9 S. x
O_TRUNC:如果文件已经存在,则删除文件的内容.
' i2 e! f; S6 {6 M* k! M6 J+ d
前面三个标志只能使用任意的一个.如果使用了O_CREATE标志,那么我们要使用open的第二种形式.还要指定mode标志,用来表示文件的访问权限.mode可以是以下情况的组合.
7 c9 o7 ?; d$ _
-----------------------------------------------------------------
0 Y0 T5 a1 Q. @! ~
S_IRUSR 用户可以读 S_IWUSR 用户可以写
- m3 j4 C5 M9 B) K( _+ \S_IXUSR 用户可以执行 S_IRWXU 用户可以读写执行
0 w1 t& a2 ]. x' B
-----------------------------------------------------------------
; y8 O2 w' x& O
S_IRGRP 组可以读 S_IWGRP 组可以写
% N" O" l3 h: D! PS_IXGRP 组可以执行 S_IRWXG 组可以读写执行
+ s5 ?6 o8 _" Q9 T, [, I-----------------------------------------------------------------
: w: B, W& t7 m E) U- v8 ^8 k$ P6 [
S_IROTH 其他人可以读 S_IWOTH 其他人可以写
# e+ R; P* o+ I' [' \5 h4 `; U4 TS_IXOTH 其他人可以执行 S_IRWXO 其他人可以读写执行
. B! w4 O4 J0 k0 P1 Y( w
-----------------------------------------------------------------
$ w% c& b% ]3 U! R& `6 m! mS_ISUID 设置用户执行ID S_ISGID 设置组的执行ID
6 }2 M: M; l- c- o) k9 {
-----------------------------------------------------------------
2 Z4 c& R4 l! P+ e( n4 _+ T
我们也可以用数字来代表各个位的标志.Linux总共用5个数字来表示文件的各种权限.
: G5 j* f7 Q# y9 P/ Y00000.第一位表示设置用户ID.第二位表示设置组ID,第三位表示用户自己的权限位,第四
! W) P, r. E# |, q4 S位表示组的权限,最后一位表示其他人的权限.每个数字可以取1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和..
2 f2 ? K! r9 g0 z3 Q# X. ~比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户ID位那么我们可以使用的模式是--1(设置用户ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省)5(1+4)即10705:
( O8 ?6 ?6 J5 B3 O6 E( u' q
open("temp",O_CREAT,10705);
2 B* _( a* q( E1 ^如果我们打开文件成功,open会返回一个文件描述符.我们以后对文件的所有操作就可以对这个文件描述符进行操作了.
/ F4 l. f X* y: X5 I0 I
当我们操作完成以后,我们要关闭文件了,只要调用close就可以了,其中fd是我们要关闭的文件描述符.文件打开了以后,我们就要对文件进行读写了.我们可以调用函数read和write进行文件的读写.
5 r5 l. o3 _% X0 {! q6 U7 o#include <unistd.h>
% K' l% m! z4 m& u
ssize_t read(int fd, void *buffer,size_t count);
& j" N6 c( q8 g, d# g
ssize_t write(int fd, const void *buffer,size_t count);
6 f4 J3 ?* o) B' l' T7 pfd是我们要进行读写操作的文件描述符,buffer是我们要写入文件内容或读出文件内容的内存地址.count是我们要读写的字节数.
5 @# _$ a3 v6 h8 C
对于普通的文件read从指定的文件(fd)中读取count字节到buffer缓冲区中(记住我们必须提供一个足够大的缓冲区),同时返回count.
+ [. I+ m$ c) Y如果read读到了文件的结尾或者被一个信号所中断,返回值会小于count.如果是由信号中断引起返回,而且没有返回数据,read会返回-1,且设置errno为EINTR.当程序读到了文件结尾的时候,read会返回0.write从buffer中写count字节到文件fd中,成功时返回实际所写的字节数.
/ s: z4 f" c5 f6 o7 e下面我们学习一个实例,这个实例用来拷贝文件.
3 C- P& f O2 ^
#include <unistd.h>
$ |3 r( R6 @* s5 D# D#include <fcntl.h>
7 l, e% I0 F% ?4 X; ]. u#include <stdio.h>
2 p" w& [5 O: {#include <sys/types.h>
- M' z4 d: M u5 h+ c {#include <sys/stat.h>
, D; q" T, U. R
#include <errno.h>
3 R9 j; a! z% D! D4 M#include <string.h>
, y6 j- R* a4 C$ g#define BUFFER_SIZE 1024
' [6 @' M6 @9 Nint main(int argc,char **argv)
+ |( A K' a9 i" H s' a
{
9 c4 W- f& e _( l
int from_fd,to_fd;
' M7 n$ k6 |, _0 C+ {( ^' [# `int bytes_read,bytes_write;
- U' q- A5 f5 Z1 \char buffer[BUFFER_SIZE];
/ \4 M4 v# N! \
char *ptr;
z, T! G% z$ d" ]& [( K3 ^
if(argc!=3)
) S5 W% e: U: h, C/ o/ }( R$ {$ T, B{
( m0 k* [9 ] P9 B. |5 V; L nfprintf(stderr,"Usage:%s fromfile tofile\n\a",argv[0]);
1 H7 V. K1 B1 D) s
exit(1);
! H! L6 {; }" @. X( b& Z9 O
}
: d. Y$ |: `: |+ y" n/* 打开源文件 */
! {: |+ r) C1 lif((from_fd=open(argv[1],O_RDONLY))==-1)
& F& N' B) Z2 G$ O' u P7 Q
{
* d8 ~# Q) k6 U; r, Ifprintf(stderr,"Open %s Error:%s\n",argv[1],strerror(errno));
, ~7 ^* ^5 t& X/ t2 I" A4 |exit(1);
7 N8 k0 V; A; Y" f% M9 w}
' [( S, M+ S7 O. H4 v/* 创建目的文件 */
. } Q9 e. t! |* n( _6 pif((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1)
: m) R8 e5 l! U8 H; k! u9 u
{
! Q% `0 ^. Q6 a1 {6 g
fprintf(stderr,"Open %s Error:%s\n",argv[2],strerror(errno));
* _$ g( g' R% F$ N, v0 [5 D
exit(1);
2 A& o2 O: `' H3 h- O* a" w}
; b- j' d/ l9 \9 s+ ?4 H4 Z3 f/* 以下代码是一个经典的拷贝文件的代码 */
% a5 v k/ F# \, N
while(bytes_read=read(from_fd,buffer,BUFFER_SIZE))
% c2 j7 @# s6 |, F# [2 Z. b. O9 ~
{
4 y( K: t3 Q, [1 ]& B
/* 一个致命的错误发生了 */
7 @5 R, |* n* s( [. y0 _if((bytes_read==-1)&&(errno!=EINTR)) break;
% U5 g" T: j0 Z' @* {: j1 v& Welse if(bytes_read>0)
* Y& U5 r( n9 V1 X9 j2 E0 z( |7 P
{
; O) I. X, A8 Rptr=buffer;
' O& l) v. V6 rwhile(bytes_write=write(to_fd,ptr,bytes_read))
8 o, J7 I0 z) J6 B4 h/ ?6 I{
$ M0 }$ C; Y9 C! l7 d/ X" [5 _/* 一个致命错误发生了 */
) t% B _% D! L
if((bytes_write==-1)&&(errno!=EINTR))break;
5 n. ?0 {2 k$ v) B/* 写完了所有读的字节 */
- O. U, ^" A. P3 y1 eelse if(bytes_write==bytes_read) break;
; E0 h5 m5 r h# q0 I; a
/* 只写了一部分,继续写 */
# U4 A. T- Y9 J' l1 x: I4 [" L6 ?
else if(bytes_write>0)
/ N; h7 M$ j' w0 ~* H$ M# n
{
& @! E4 g, k9 @7 c3 H% U/ n9 T
ptr+=bytes_write;
5 C, f3 q* Z$ S( r5 o
bytes_read-=bytes_write;
4 |/ |6 p, ~0 Z, n6 O V3 a4 z$ J}
; q7 H4 ^# X2 ^( _; I5 o
}
}* ?, R8 P a! X2 M6 o& u/* 写的时候发生的致命错误 */
6 k9 l# J4 Q6 o8 d7 B @
if(bytes_write==-1)break;
& `5 o- f/ Q4 K
}
" D0 m O% ], V% E, t e' d9 A9 ]}
0 [: p/ A c' c" T& A
close(from_fd);
7 t8 X* w* G' n8 B g
close(to_fd);
( F# t: o% u( z( h4 h& D0 zexit(0);
" H( I" H: ?$ a" I# s; T
}
) A, b2 A, ^/ N5 U8 C: d2。文件的各个属性
; b n3 u+ e8 _* ^文件具有各种各样的属性,除了我们上面所知道的文件权限以外,文件还有创建时间,大小等等属性.
$ `0 c- f7 K, d有时侯我们要判断文件是否可以进行某种操作(读,写等等).这个时候我们可以使用access函数.
+ z; ^3 Z. _8 Z#include <unistd.h>
$ F2 @8 B' \: s* r1 ^( g' k; [' I3 s' h- X& D4 j1 c b
int access(const char *pathname,int mode);
$ f' S/ e: }+ Z6 Vpathname:是文件名称,mode是我们要判断的属性.可以取以下值或者是他们的组合.
0 y' o X, M. s: N0 F
R_OK文件可以读,W_OK文件可以写,X_OK文件可以执行,F_OK文件存在.当我们测试成功时
& }; H. a+ M. M) \: |4 T
,函数返回0,否则如果有一个条件不符时,返回-1.
6 {- I7 ^$ f+ @, a- |! I) N
如果我们要获得文件的其他属性,我们可以使用函数stat或者fstat.
- D/ Q" P9 U- I! q" v+ L#include <sys/stat.h>
6 p7 ~7 A7 t+ A) b' C& f( U. s#include <unistd.h>
) [/ V3 e" V: w6 T' I
int stat(const char *file_name,struct stat *buf);
7 G9 w( A" X' m3 e2 Y/ _* W
int fstat(int filedes,struct stat *buf);
( W* O& I" x+ A. T5 r7 Fstruct stat {
$ h E5 H- v/ W( [$ b" odev_t st_dev; /* 设备 */
8 M5 ^9 |1 H9 d! ~, _
ino_t st_ino; /* 节点 */
% ?$ ~7 C3 s7 V6 j0 d0 B- z4 Hmode_t st_mode; /* 模式 */
/ @0 |) k) `3 g* j! s
nlink_t st_nlink; /* 硬连接 */
0 c9 w& L+ s/ v$ f
uid_t st_uid; /* 用户ID */
2 h3 D+ a9 M& D
gid_t st_gid; /* 组ID */
9 W+ N9 @2 ^" W) w1 X Wdev_t st_rdev; /* 设备类型 */
; D6 U. X6 ?3 p9 }* i$ ^ M3 h3 _off_t st_off; /* 文件字节数 */
3 o" e" R/ y* x4 Gunsigned long st_blksize; /* 块大小 */
( D$ ~- d! J8 {$ ? o) l) W
unsigned long st_blocks; /* 块数 */
1 Z' s2 c7 O8 Z2 V8 x1 O
time_t st_atime; /* 最后一次访问时间 */
* D3 x& c/ G3 i; q/ ^ b
time_t st_mtime; /* 最后一次修改时间 */
; e' |" W. D% P/ Ftime_t st_ctime; /* 最后一次改变时间(指属性) */
5 \* z8 ~' P+ [ W};
, p) S& W3 E/ q6 @3 Y: b
stat用来判断没有打开的文件,而fstat用来判断打开的文件.我们使用最多的属性是st_mode.通过着属性我们可以判断给定的文件是一个普通文件还是一个目录,连接等等.可以使用下面几个宏来判断.
% k- l! P; G$ w! B1 w# A' ~S_ISLNK(st_mode):是否是一个连接.S_ISREG是否是一个常规文件.S_ISDIR是否是一个目
' x& P, s0 G. g录S_ISCHR是否是一个字符设备.S_ISBLK是否是一个块设备S_ISFIFO是否 是一个FIFO文
) i. |% D$ N d" y3 n" Y1 v, k o件.S_ISSOCK是否是一个SOCKET文件. 我们会在下面说明如何使用这几个宏的.
& O" _, [- e+ u4 L6 X3 T
: J- p9 }0 v1 C8 `3 u* S
3。目录文件的操作
' O( o( B: S: Y在我们编写程序的时候,有时候会要得到我们当前的工作路径。C库函数提供了getcwd来解决这个问题。
8 n0 y# [6 u# Q% S3 P" J#include <unistd.h>
5 m7 S6 l: N& p0 `! T7 S
0 I0 H7 m% R! z0 p9 w, rchar *getcwd(char *buffer,size_t size);
# k4 n1 }* s+ c f3 Q h
我们提供一个size大小的buffer,getcwd会把我们当前的路径考到buffer中.如果buffer太小,函数会返回-1和一个错误号.
: P9 V6 Y9 I: mLinux提供了大量的目录操作函数,我们学习几个比较简单和常用的函数.
! j7 G* j J- r0 c' l3 H#include <dirent.h>
* q( C- S$ ]( w3 e* h8 D3 d
#include <unistd.h>
5 ^ z* c9 ~4 q2 U# g' G, Y#include <fcntl.h>
2 q. Y( n( @5 H2 g3 N7 b#include <sys/types.h>
' m& D1 E" g/ \4 R2 L& v#include <sys/stat.h>
8 S" j1 b0 t+ Mint mkdir(const char *path,mode_t mode);
6 ~: x. a: e! o1 c
DIR *opendir(const char *path);
2 z* e; F B6 Q' d& U2 M/ R
struct dirent *readdir(DIR *dir);
. P2 ?, J+ T* t! u; G9 Q, e5 j
void rewinddir(DIR *dir);
1 N# ~9 F7 m, T) `6 ?
off_t telldir(DIR *dir);
0 V B0 i0 V% Nvoid seekdir(DIR *dir,off_t off);
- b3 |9 _+ c# v" kint closedir(DIR *dir);
+ w5 j' U8 K5 e) ]3 \' r
struct dirent {
! h# o4 Y6 r+ ?# k4 M' K& g1 b* J
long d_ino;
( O! Q# z% D4 _+ f' ?/ L; roff_t d_off;
1 ^6 j) [ h2 [. P) xunsigned short d_reclen;
; o! R8 W+ a% |" a6 W
char d_name[NAME_MAX+1]; /* 文件名称 */
% ~" Z+ |& F- imkdir很容易就是我们创建一个目录,opendir打开一个目录为以后读做准备.readdir读一个打开的目录.rewinddir是用来重读目录的和我们学的rewind函数一样.closedir是关闭一个目录.telldir和seekdir类似与ftee和fseek函数.
& I; k2 t5 W. y9 q* N% _4 ?0 B下面我们开发一个小程序,这个程序有一个参数.如果这个参数是一个文件名,我们输出这个文件的大小和最后修改的时间,如果是一个目录我们输出这个目录下所有文件的大小和修改时间.
7 {6 I2 @6 \6 e$ W9 f% v& x
#include <unistd.h>
3 Q, E" i( ~" `
#include <stdio.h>
0 s5 @9 ^. _: v1 Z0 T#include <errno.h>
3 @& Y/ @( u0 n' ^
#include <sys/types.h>
! E3 @( V1 h& }# p$ ~! h#include <sys/stat.h>
9 Y! i6 G% x9 z
#include <dirent.h>
7 x* ~" P4 k+ {: ]3 ^3 z
#include <time.h>
2 S4 i( Y2 T' `7 H7 F( u3 w$ @* s( _static int get_file_size_time(const char *filename)
+ Q3 Z& D$ V9 p$ s4 G; T9 ]
{
, u3 k# a/ r! f7 j
struct stat statbuf;
: y% S; q" R$ ?, }5 K5 a5 p
if(stat(filename,&statbuf)==-1)
+ N) Y. l& H. @$ Y) |$ o+ E{
$ y/ Q8 Z, ~. D3 {printf("Get stat on %s Error:%s\n",
9 [& v1 T$ f0 Xfilename,strerror(errno));
' P7 z4 f4 ^! K( x' V6 f/ u
return(-1);
, d+ X8 V9 e( d7 o% s b/ a) q}
3 s/ r% N" o1 A% w6 Sif(S_ISDIR(statbuf.st_mode))return(1);
2 W* J2 s* j! P% bif(S_ISREG(statbuf.st_mode))
! m4 D1 G/ _" G- Q
printf("%s size:%ld bytes\tmodified at %s",
( r, p* r- V6 _: Z7 r6 l+ Bfilename,statbuf.st_size,ctime(&statbuf.st_mtime));
! F9 Z8 M& ]) w9 G2 b, F6 g. G n+ h6 T
return(0);
3 u W, }8 J4 O, d}
) F" a5 ~* w; y. I! M+ Qint main(int argc,char **argv)
4 H% _5 P2 k* e" ?2 p
{
/ V" Z) d5 H) I* [ l. YDIR *dirp;
/ X ^( d! w' M; m# E2 k6 M2 U
struct dirent *direntp;
" C1 [" J7 o8 Y% l
int stats;
' w; b$ Z5 e( c% U7 c" H! @4 G1 f
if(argc!=2)
1 }# z: D# Y2 T' J# `9 o4 ~& q{
( L/ K9 H) s6 I x$ Jprintf("Usage:%s filename\n\a",argv[0]);
! u1 O; }; l! y" h' L+ G& Aexit(1);
& c$ w5 R* h: K% V1 X( L& @
}
4 _1 |' u; ~3 ^; }) ~) k/ wif(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))exit(1);
% H- e* G( R! z0 h
if((dirp=opendir(argv[1]))==NULL)
2 X; M* { F) @% ^6 D{
% x' e* ]7 M3 U9 E% R( {- p$ I# Wprintf("Open Directory %s Error:%s\n",
# q) V" g* p) u$ N" |argv[1],strerror(errno));
4 I$ g. {' z* Lexit(1);
/ v* Y( J4 e# m; h" \' l}
3 I% L0 M0 O6 j9 \while((direntp=readdir(dirp))!=NULL)
3 E! a5 X0 B4 V! X3 b5 v9 M7 p
if(get_file_size_time(direntp-<d_name)==-1)break;
1 m* Y, M$ J/ |: T4 g) Zclosedir(dirp);
8 N: }) O: y7 d. X; ^# aexit(1);
0 E! F/ H" d; H. r7 H
}
- b) a1 b' N+ t/ v: D4。管道文件
; K! n% S' ]2 yLinux提供了许多的过滤和重定向程序,比如more cat等等.还提供了< > | <<等等重定向操作符.在这些过滤和重 定向程序当中,都用到了管道这种特殊的文件.系统调用pipe可以创建一个管道.
8 j. {4 @" G4 n#include<unistd.h>
% {' h' ] H& `8 y8 ^, e$ K
- z0 z0 a& _9 G3 ~- p3 a
int pipe(int fildes[2]);
+ u I6 c" p1 U- q2 C1 e
pipe调用可以创建一个管道(通信缓冲区).当调用成功时,我们可以访问文件描述符fildes[0],fildes[1].其中fildes[0]是用来读的文件描述符,而fildes[1]是用来写的文件描述符.
: o0 F' j* u2 a0 B/ |5 A在实际使用中我们是通过创建一个子进程,然后一个进程写,一个进程读来使用的.
3 K) b; b5 e$ @' s. x
关于进程通信的详细情况请查看进程通信
6 D( e( b) I' N0 |# T7 w W. W
#include <stdio.h>
" m {+ m" ~$ y) A+ j
#include <stdlib.h>
1 ]: k- T$ y5 I2 M. C" h! J
#include <unistd.h>
0 J( Z4 K& I! n! o6 [: g#include <string.h>
3 \* [' H3 u4 [- b' a- H/ X#include <errno.h>
, `. P, |% Q! ^/ W& _
#include <sys/types.h>
) M" o2 V6 p# r& w9 b
#include <sys/wait.h>
% {6 M: `1 ]# s2 l8 F# N#define BUFFER 255
1 z+ g' N6 P' [, m4 w H* Fint main(int argc,char **argv)
, a# }7 ^) D8 e! H( Z
{
x. h& H& G/ J1 `+ g- p, Q0 |
char buffer[BUFFER+1];
4 Y- D+ l/ ]9 P7 n! ^+ L
int fd[2];
* u% F0 t) l4 J/ e
if(argc!=2)
& |9 E: @ a& B9 t% Q8 I
{
: u: n L0 d, Pfprintf(stderr,"Usage:%s string\n\a",argv[0]);
( V; d3 a& E) |) ^' r$ i
exit(1);
' A' Q w( m8 X5 p- B; A+ G
}
! p, p5 G& o% H0 p
if(pipe(fd)!=0)
8 ^2 ?% k2 S9 w# [0 @
{
8 U4 M8 \) E9 H# b+ _fprintf(stderr,"

ipe Error:%s\n\a",strerror(errno));
( z( A# p2 ^! d; o Z0 Xexit(1);
! ?. |! z- r3 `
}
/ i& ^+ G3 f. N8 pif(fork()==0)
# T& X4 f3 e P9 o. O8 ~4 W g4 r
{
0 f) E2 l ?3 w; e3 U1 i1 c, iclose(fd[0]);
* m: w! p0 }- i- k. D% g# k8 ~' F0 h
printf("Child[%d] Write to pipe\n\a",getpid());
/ v8 T* u4 x! P* V2 K( Osnprintf(buffer,BUFFER,"%s",argv[1]);
2 a' r; d; s: }0 e4 b0 t9 L
write(fd[1],buffer,strlen(buffer));
* A) Y6 E/ L1 b3 G1 i! m" Y
printf("Child[%d] Quit\n\a",getpid());
3 Y- W+ N( y1 `: T! n' h! }- |( zexit(0);
( s0 e5 V" m( Y
}
+ M* J! K( s9 B8 a# o, O9 belse
, Y! J; y/ Q9 `' t1 l; o# u% |{
7 `( v) B2 g& d3 k
close(fd[1]);
! C) F+ S! E& j/ ?8 ~printf("

arent[%d] Read from pipe\n\a",getpid());
. W( T3 m& e) H# i
memset(buffer,'\0',BUFFER+1);
+ n# s' u; O4 ]# r" W$ W6 X
read(fd[0],buffer,BUFFER);
0 h0 O( p# e0 y$ X; G% h% v% ?
printf("

arent[%d] Read:%s\n",getpid(),buffer);
8 ?9 W- t- T7 O4 M5 M. Q; h+ Mexit(1);
- c0 U3 o* \6 v6 \ {}
- s( ]0 E* H3 R+ a}
" i j3 P- a, @( y为了实现重定向操作,我们需要调用另外一个函数dup2.
- N( }/ b8 v1 K! X' A9 ~#include <unistd.h>
, a# R w/ h1 R. w* h* R' ]" t9 H: y$ S) r
int dup2(int oldfd,int newfd);
5 p1 [8 }5 }" @0 s, h/ Sdup2将用oldfd文件描述符来代替newfd文件描述符,同时关闭newfd文件描述符.也就是说,
9 W3 x+ i' |% y. C p
所有向newfd操作都转到oldfd上面.下面我们学习一个例子,这个例子将标准输出重定向到一个文件.
7 r+ A5 h! y8 D$ e4 P8 c! }#include <unistd.h>
, ^' O% F/ }9 @1 S6 V: c1 |, q; f#include <stdio.h>
5 T* M7 a& a1 L' I#include <errno.h>
# r2 o6 b" S7 ]" b, F
#include <fcntl.h>
9 a5 d- X# x0 B# a0 ^, @) e#include <string.h>
+ p# x6 r4 v( A2 H) j#include <sys/types.h>
$ T! \( R3 m! K" u#include <sys/stat.h>
# t: o5 o8 D# q2 \" u#define BUFFER_SIZE 1024
! s* @1 A1 e3 @: y! k8 gint main(int argc,char **argv)
* ~, a/ K& ]& N: Z/ {, V7 L{
! a- g' Q+ R% a6 fint fd;
' n5 V9 c) C5 I+ e
char buffer[BUFFER_SIZE];
) J9 T) L# i0 t; [: C
if(argc!=2)
8 v9 C# K- {4 ?* e
{
/ g. J2 H8 n2 E, N. I
fprintf(stderr,"Usage:%s outfilename\n\a",argv[0]);
4 w) c" U" \ }3 z7 u$ s0 Pexit(1);
9 A8 v/ V2 @8 l& u) E4 y; s
}
0 F+ n$ f6 v+ J$ | q) a
if((fd=open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1)
" N( q+ d- J4 i: d% _9 o; t0 { g
{
- S; S" g& y) ]. h" L
fprintf(stderr,"Open %s Error:%s\n\a",argv[1],strerror(errno));
4 h0 h( T: F" B0 zexit(1);
2 p7 h' p8 G5 {) w# f3 P}
" [4 a) y7 S: L& o. a4 ^! F7 A
if(dup2(fd,STDOUT_FILENO)==-1)
z2 n9 X. V# D9 V* |% s{
! b$ R9 J b/ ?' w& ^. x) l0 C {
fprintf(stderr,"Redirect Standard Out Error:%s\n\a",strerror(errno));
' ~/ t) f1 E T
exit(1);
5 |. L* h9 S0 p) F3 L z+ M2 X' j}
7 K9 }7 Z" o7 hfprintf(stderr,"Now,please input string");
/ S# F% W9 p: r" _ w* k
fprintf(stderr,"(To quit use CTRL+D)\n");
7 s( L! V9 m) P+ F% x" s. k/ u. C1 rwhile(1)
- H4 R! j( A+ \ v$ x" v* f{
) b* f& j1 d. F7 {
fgets(buffer,BUFFER_SIZE,stdin);
1 J6 K# {6 T( q& x" v( |) t
if(feof(stdin))break;
6 t. |" P1 j2 S* m9 j( Q. Vwrite(STDOUT_FILENO,buffer,strlen(buffer));
2 C8 x# U6 V4 F; `5 x7 \}
# O7 s, W' T0 v s& aexit(0);
, V4 O0 i2 i/ K
}
: k6 w1 c, v r4 |- z% |
好了,文件一章我们就暂时先讨论到这里,学习好了文件的操作我们其实已经可以写出一些比较有用的程序了.我们可以编写一个实现例如dir,mkdir,cp,mv等等常用的文件操作命令了.
1 y- `6 V# t+ S- I( T" Y想不想自己写几个试一试呢?