Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1736416
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: Python/Ruby

2012-03-26 11:44:37

前面已经提过文件的读写,包括只读模式(open(HANDLE, "filename")),覆盖模式(open(HANDLE, ">filename"))和追加模式(open(HANDLE, ">>filename"))。另一种模式是读写模式:用“+>”或“+<”表示:

  1. # 打开读写文件
  2. open (FILE, "+>tmp") || die ("Failed to open tmp");
  3. print FILE "content";
  4. $pos = tell(FILE); # tell表示当前位置离文件头的字节数
  5. print "pos: $pos\n"; # 7
  6. seek(FILE, 0, 0); # seek第二个参数为偏移的字节数,第三个参数是起始位置,0为从文件头开
  7. 始移动,1为从当前位置移动,2为从文件末尾移动。
  8. while (!eof(FILE)) {
  9.     print getc(FILE); # content
  10. }
  11. close FILE;

还有一种管道模式:利用管道符(|)打开一个管道,把输入到管道的数据作为另一个进程的标准输入(open (HANDLE, "|command")),或从管道中读取另一个进程的标准输出(open (HANDLE, "command|"))。下面是一个例子,程序名为pipeline.pl:


  1. #!/usr/bin/perl
  2. $mode = $ARGV[0];

  3. if ($mode eq "push") {
  4.     if (open(PIPELINE, "|./pipeline.pl push_read")) {
  5.         print PIPELINE "Push to another process\n";
  6.         close(PIPELINE);
  7.     }
  8. } elsif ($mode eq "push_read") {
  9.     while (<STDIN>) {
  10.         print "=Read=: $_";
  11.     }
  12. } elsif ($mode eq "pull") {
  13.     if (open (PIPELINE, "./pipeline.pl pull_write|")) {
  14.         while (<PIPELINE>) {
  15.             print "=Read=: $_";
  16.         }
  17.         close (PIPELINE);
  18.     }
  19. } elsif ($mode eq "pull_write") {
  20.     print "Pull from another process.\n";
  21. } else {
  22.     die "invalid mode";
  23. }

输入命令pipeline.pl push得到下列结果:
=Read=: Push to another process

而命令pipeline.pl pull得到:
=Read=: Pull from another process.

利用open函数还可以实现文件的重定向,下面的代码把STDOUT和STDERR的输出都重定向到一个名为tmp的文件中:


  1. # 重定向标准输出
  2. open (STDOUT, ">tmp") || die ("Failed to open STDOUT");
  3. open (STDERR, ">&STDOUT") || die ("Failed to open STDERR");
  4. print STDOUT "line 1\n";
  5. print STDERR "line 2\n";
  6. close STDOUT;
  7. close STDERR;

上面的代码可以在终端用一行命令简单的完成:foo > tmp 2>&1。其中foo为任意命令。

变量$|用来表示当前输出目标是否使用缓存。如果$|设为1则表示不使用缓存,类似于每次输出后进行一个flush操作:


  1. $| = 1; # 为STDOUT设置强制输出
  2. select STDERR;
  3. $| = 1; # 为STDERR设置强制输出


除了用print和getc来读写字符文件,还可以使用read,write来读写文件:

  1. $file = "FILE"; # 使用变量来打开文件
  2. open ($file, "+) or die ("Failed to open tmp");
  3. format DATA =
  4. @<@>>
  5. 25, abd
  6. .

  7. $savedOut = select $file;
  8. $savedFormat = $~;
  9. $~ = "DATA";
  10. write;
  11. $~ = $savedFormat;
  12. select $savedOut;

  13. seek($file, 0, 0);
  14. read ($file, $num, 2, 0); # read(filevar, result, length, skipval),第一个参数是文件变量,第二个参数是存储读取结果的变量,第三个参数是读取的字符数,第四个参数是读文件之前跳过的字节数(可选)。
  15. print $num."\n"; # 25
  16. read ($file, $string, 3);
  17. print $string."\n"; # abd
  18. close $file;

  19. read等同于Unix的fread函数。sysread和syswrite等同于Unix的read和write函数,读写速度更快:

  20. open (FILE, "+>tmp") || die ("Failed to open tmp");
  21. syswrite(FILE, 63, 2, 0);
  22. seek(FILE, 0, 0);
  23. sysread(FILE, $num, 2, 0);
  24. print $num."\n"; # 63


 
当你的系统(如类DOS系统)对文本文件和二进制文件有所区别时可以使用binmode (filevar)。必须在打开文件后、读取文件前使用。

对目录进行的操作


  1. # 目录处理
  2. mkdir ("mydir"); # 创建目录
  3. chdir ("mydir"); # 改变当前工作目录
  4. mkdir ("subdir1"); # 在mydir中创建目录
  5. mkdir ("subdir2");
  6. mkdir ("subdir3");
  7. open (SUBFILE, ">subfile1") and print SUBFILE "sub file 1", close SUBFILE;
  8. open (SUBFILE, ">subfile2") and print SUBFILE "sub file 2", close SUBFILE;

  9. chdir (".."); # 回到mydir的父目录
  10. opendir (MYDIR, "mydir") or die ("open mydir failed");
  11. while ($file = readdir(MYDIR)) {
  12.     print $file . " | "; # .. | subdir3 | subdir2 | subfile2 | . | subfile1 | subdir1 |
  13. }

  14. rewinddir MYDIR; # 让读取目录的位置重置回到开头
  15. readdir(MYDIR)."\n"; # 忽略第一个子目录
  16. $location = telldir(MYDIR); # 得到当前读取目录的位置
  17. print "location: $location\n"; # location: 605303214
  18. readdir MYDIR; # subdir3
  19. @files = readdir(MYDIR); # 读取之后所有的文件和子目录名
  20. print "@files\n"; # subdir2 subfile2 . subfile1 subdir1
  21. print "End\n" unless readdir(MYDIR); # End
  22. seekdir(MYDIR, $location); #重新回到之前位置,location必须是telldir的返回值
  23. print readdir(MYDIR)."\n"; # subdir3
  24. closedir MYDIR;

mkdir其实可以有第二个参数(mkdir(dirname, permissions))。permissions是一个八进制数,它可以是下列的某个值或某些值的和:

  权限
4000   运行时设置用户ID  
2000 运行时设置组ID
1000 粘贴位
0400 拥有者读权限
0200 拥有者写权限
0100 拥有者执行权限
0040 组读权限
0020 组写权限
0010 组执行权限
0004 所有人读权限
0002 所有人写权限
0001 所有人执行权限

文件属性的函数:
  1.     # 重命名一个目录
  2.     rename ("mydir/subdir1", "mydir/subdir6") or print "faied to rename subdir1\n";
  3.     # 移动一个目录
  4.     rename ("mydir/subdir3", "subdir3") or print "failed to rename subdir3\n";
  5.     # 重命名一个文件
  6.     rename ("mydir/subfile1", "mydir/new_subfile") or print "failed to rename subfile1\n";
  7.     # 移动一个文件
  8.     rename ("tmp", "mydir/tmp") or print "failed to rename tmp";

  9.     # 硬链接
  10.     link ("mydir/subfile2", "linkfile") or print "failed to link subfile2\n";
  11.     # 软链接
  12.     symlink ("mydir/subfile2", "shotcut") or print "failed to symlink subfile2\n";
  13.     # 得到软链接指向的文件
  14.     print readlink("shotcut")."\n"; # mydir/subfile2
  15.     # 删除文件(因为实际上是删除文件的一个链接所以得此名)
  16.     print unlink ("mydir/subfile2")."\n"; # 1 返回值为删除文件的个数

  17.     # 改变文件访问权限
  18.     chmod (777, "mydir/tmp"); # chmod(permissions, filelist),permissions的值和mkdir中permissions的取值一样
  19.     # 改变文件的属主
  20.     chown (1, 2, "mydir/tmp"); # chown(usrid, groupid, filelist)。usrid为新属主的ID号,groupid是新的组的ID号
  21.     # 改变文件访问权限掩码,返回当前掩码
  22.     $oldmask = umask(18);

  23.     # 将文件的长度减少到length字节。如果文件长度已经小于length,则不做任何事。
  24.     truncate ("linkfile", 20);
  25.     # 获取文件状态
  26.     @states = stat ("mydir"); # states: 2049 528335 16877 4 1000 1000 0 4096 1322216914 1322216904 1322216904 4096 8
  27.     print "states: @states\n";
  28.     # 将文件看作符号链接并获得状态
  29.     @states = lstat ("shotcut"); # 2049 399968 41471 1 1000 1000 0 14 1322215928 1322215927 1322215927 4096 0
  30.     print "states: @states\n";

stat和lstat的返回值是列表,里面的值依次为:
  • 文件所在设备
  • 内部参考号(inode)
  • 访问权限
  • 硬链接数
  • 属主的(数字)ID
  • 所属组的(数字)ID
  • 设备类型(如果file是设备的话)
  • 文件大小(字节数)
  • 最后访问时间
  • 最后修改时间
  • 最后改变状态时间
  • I/O操作最佳块大小
  • 分配给该文件的块数

  • 其它几个文件相关的函数:
    函数名 fileno
    调用语法 filedesc = fileno (filevar);
    解说 返回文件的内部UNIX文件描述。参数filevar为文件变量。
    函数名 fcntl
    flock
    调用语法 fcntl (filevar, fcntlrtn, value);
    flock (filevar, flockop);
    解说 详见同名UNIX函数帮助。

    与时间相关的函数:


    1.     # 获得当前时间,从1970年1月1日起累计秒数
    2.     print time()."\n"; # 1322218075

    3.     # 把秒数转换成格林威治时间,返回一个列表。元素依次为:
    4.     # 秒\分钟\小时(0~23)\日期\月份(0~11)\年份\星期(0~6)\一年中的日期(0~364)\是否夏令时的标志
    5.     @time = gmtime(time());
    6.     print join("-", @time)."\n"; # 55-47-10-25-10-111-5-328-0

    7.     # 把秒数转换为本地时间,与gmtime相似
    8.     @time = localtime(time());
    9.     print join("-", @time)."\n"; # 55-47-18-25-10-111-5-328-0

    10.     # 改变文件的最后访问时间和最后更改时间
    11.     $accesstime = -A "linkfile"; # 距离现在的天数
    12.     $modifiedtime = -M "linkfile"; # 距离现在的天数
    13.     $accesstime = time() - $accesstime*24*60*60;
    14.     $modifiedtime = time() - $modifiedtime*24*60*60;
    15.     utime ($accesstime, $modifiedtime, "other");

    关联数组与文件


    1. # 将数组与文件关联
    2. dbmopen (%hash, "data", 666); # dbmopen (array, dbmfilename, permissions)
    3. $hash{"a"} = "hello";
    4. $hash{"b"} = 34;
    5. dbmclose (%hash);
    6. dbmopen (%result, "data", 666);
    7. print $result{"b"}."\n"; # 34
    8. dbmclose (%result);

    9. # Perl 5中用tie和untie取代dbmopen和dbmclose
    10. use Tie::File;

    11. my @array = ();
    12. tie(@array, 'Tie::File', "data");
    13. @array[0] = "tie";
    14. @array[1] = "untie";
    15. @array[5] = "data";
    16. untie (@array); # tie untie data
    17. tie(@result, 'Tie::File', "data");

    阅读(1155) | 评论(0) | 转发(1) |
    给主人留下些什么吧!~~