这篇博文中的程序  将要示范  如何编写  一个命令行工具,从而  实现  简单的复制文件操作。这项命令的用法  可以是  这样:

与  适用于NSFileManager这类物件的措施copyPath:toPath:handler:  不同,copy这项命令  允许  目标  可以是  目录名称。另外一点不同的  是  如果  目标文件  已经存在,那么  copy这项命令  将会用  来源文件  覆盖  目标文件。这一点  跟标准UNIX复制命令cp  是  一致的。

你  可以通过主程序main()函数的两个参数argc  和  argv  从命令行中  获取  来源文件  和  目标文件的路径名称。这两个参数  包含了  若干命令行参数(包括  命令名称),以及  存储着c语言字符串地址的指针。

与其需要处理  c语言字符串,还不如使用  基础框架所提供的NSProcessInfo这类物件。有  不少措施  适用于  NSProcessInfo这类物件,这些措施  可以帮  你  设定、读取  你所正在运行的程序(也就是  你的进程)的各种信息。这些措施  总结  在下面的表格当中:

 

措施名称

描述

+(NSProcessInfo *)processInfo

创建NSProcessInfo类型的物件

-(NSArray *)arguments

获取当前程序的命令行参数

-(NSDictionary *)environment

获取当前环境变量

-(int)processIdentifier

获得当前进程识别号码

-(NSString *)processName

获取当前进程名称

-(NSString *)globallyUniqueString

用来生成随机字符串,可用作临时文件名称

-(NSString *)hostName

获取主机系统名称

-(NSUInteger)operatingSystem

获取代表操作系统的整数值,比如5代表mac系统

-(NSString *)operatingSystemName

获取操作系统的名称

-(NSString *)operatingSystemVersionString

获取操作系统版本

-(void)setProcessName:(NSString *)name

将进程名称设定为name

下面看看  如何编写  copy这个程序:


#import <Foundation/NSArray.h>





#import <Foundation/NSFileManager.h>





#import <Foundation/NSAutoreleasePool.h>





#import <Foundation/NSPathUtilities.h>





#import <Foundation/NSProcessInfo.h>





int                  main                  (         int                  argc         ,                  const         char                  *                  argv         [         ]         )





{





             NSAutoreleasePool                  *pool         =         [         [         NSAutoreleasePool         alloc         ]                  init         ]         ;





             NSFileManager                  *myFileManager         ;





             NSString                  *source         ,         *destination         ;





             BOOL                  isDirectory         ;





             NSProcessInfo                  *myProcessInfo         =         [         NSProcessInfo         processInfo         ]         ;





             NSArray                  *myArguments         =         [         myProcessInfo         arguments         ]         ;





             myFileManager         =         [         NSFileManager         defaultManager         ]         ;





             if         (         [         myArguments         count         ]         !=         3         )





             {





                 NSLog         (         @"用法:%@ 来源 目标"         ,         [         myProcessInfo         processName         ]         )         ;





                 return                  1         ;





             }





             source         =         [         myArguments                  objectAtIndex         :         1         ]         ;





             destination         =         [         myArguments                  objectAtIndex         :         2         ]         ;





             if         (         [         myFileManager                  isReadableFileAtPath         :         source         ]         ==         NO         )





             {





                 NSLog         (         @"无法读取来源文件%@。"         ,         source         )         ;





                 return                  2         ;





             }





             [         myFileManager                  fileExistsAtPath         :         destination                  isDirectory         :         &         isDirectory         ]         ;





             if         (         isDirectory         ==         YES         )





             {





                 destination         =         [         destination                  stringByAppendingPathComponent         :         [         source         lastPathComponent         ]         ]         ;





             }





             [         myFileManager                  removeFileAtPath         :         destination                  handler         :         nil         ]         ;





             if         (         [         myFileManager                  copyPath         :         source                  toPath         :         destination                  handler         :         nil         ]         ==         NO         )





             {





                 NSLog         (         @"复制失败!"         )         ;





                 return                  3         ;





             }





             NSLog         (         @"将%@复制到%@成功!"         ,         source         ,         destination         )         ;





             [         pool         drain         ]         ;





             return                  0         ;





}



为了能够  在命令行中  使用  copy这个命令,我们  需要将  可执行文件copy  复制  到/usr/bin当中。在命令行中  输入  open “/usr/bin”,就可以打开  /usr/bin这个目录了。我们  先试试执行  copy这项命令,同时  不附带 来源文件名称  和  目标文件名称:


koeris-Mac-mini:~ Zijin$ copy        


         2012-05-17 16:03:23.113 copy[8534:707] 用法:copy 来源 目标



再来  复制  一个不存在的文件:

koeris-Mac-mini:~ Zijin$ copy file1 file2        


         2012-05-17 16:04:22.088 copy[8536:707] 无法读取来源文件file1。




接着  复制  一个存在的文件

koeris-Mac-mini:~ Zijin$ copy /Users/Zijin/Downloads/gnucash-2.4.10.tar.bz2 /Users/Zijin/Desktop        


         2012-05-17 16:17:26.425 copy[8557:707] 将/Users/Zijin/Downloads/gnucash-2.4.10.tar.bz2复制到/Users/Zijin/Desktop/gnucash-2.4.10.tar.bz2成功!

在这个程序的


NSArray                  *myArguments         =         [         myProcessInfo         arguments         ]         ;



这行语句当中,我  对  myProcessInfo这个物件  采取了  arguments这项措施,arguments这项措施  会将  包含着字符串物件的数组物件  存储  在myArguments当中。myArguments这个数组物件中的第零个物件  是  进程名称,剩余的物件  是  命令行中输入的参数。


if         (         [         myArguments          count         ]         !=         3         )





             {





                 NSLog         (         @"用法:%@ 来源 目标"         ,         [         myProcessInfo          processName         ]         )         ;





                 return                   1         ;





             }



这几行语句  先检查  myArguments这个数组物件  是否包含了  三个元素,也就是  检查  用户  是否输入了  两个参数。如果  用户  并没有输入  两个参数,也就是  myArguments这个数组物件  并不包含  三个元素,那么  程序  就提醒  用户  copy这项命令的用法,并且  终止  程序,将  整数值1  传递  给系统。

如果  用户  确实  输入了  两个参数,那么  继续执行  下面的语句:

source         =         [         myArguments                  objectAtIndex         :         1         ]         ;





destination         =         [         myArguments                  objectAtIndex         :         2         ]         ;




对  myArguments这个物件  采取  objectAtIndex:这项措施,分别  将  1  和  2  用作  参数,从而  将  myArguments这个数组物件中的第1个  和  第2个物件(也就是  用户在命令行中输入的来源文件名称  和  目标文件名称)读取出来,并且  分别  存储  在source  和  destination。接着

[         myFileManager                   fileExistsAtPath         :         destination                   isDirectory         :         &         amp         ;         isDirectory         ]         ;




这行语句  会判断  目标文件  是否是  目录。如果  目标文件  是  目录,那么  就将  变量isDirectory的值  设定为 YES。

接着

if         (         isDirectory         ==         YES         )





{





             destination         =         [         destination                  stringByAppendingPathComponent         :         [         source         lastPathComponent         ]         ]         ;





}




会判断  变量isDirectory的值  是否为  YES。如果  变量isDirectory的值  为  YES,那么  表明  目标文件  是  目录。所以  就会执行


destination         =         [         destination                   stringByAppendingPathComponent         :         [         source          lastPathComponent         ]         ]         ;



这行语句。其中


[         source         lastPathComponent         ]



将  来源文件中最后一个组成部分(也就是  文件名)  读取出来。比如  /Users/Zijin/Downloads/gnucash-2.4.10.tar.bz2的最后一个组成部分  就是  gnucash-2.4.10.tar.bz2。

stringByAppendingPathComponent:这项措施的实施对象destination  是  目标文件(或者  目标路径),其参数  为  不包含路径的来源文件名称。stringByAppendingPathComponent:这项措施  将  不包含路径的来源文件名称  附加  在目标路径的末尾处,从而  构成  完整的目标文件。

由于  如果  目标文件  已经存在,而  copyPath:toPath:handler:这项措施  无法用  来源文件  覆盖  已有的目标文件,所以  为了避免  错误,我们  可以采取  removeFileAtPath:handler:这项措施  将  已存在的目标文件  删除,就像  这样:



[         myFileManager                  removeFileAtPath         :         destination                  handler         :         nil         ]         ;



程序剩余的部分  其实  已经不言自明了,这里  就不再  赘述了。