精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>资料汇编----------藏经阁>>Unix编程FAQ>>Unix编程FAQ第2章8-10

主题:Unix编程FAQ第2章8-10
发信人: tengel()
整理人: kevintz(2000-08-24 02:00:26), 站内信件
2.8如何得到一个文件的大小
如果你打开了文件,使用stat或者fstat.
这些调用填充所有系统保留的的该文件的信息;像文件的所有者,组,权限,大小,最

后访问时间,最后修改时间,等等.
下面的例程详述的使用stat得到文件的大小.
#include <stdlib.h>
#include <stdio.h>

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

int get_file_size(char *path,off_t *size)
{
  struct stat file_stats;

  if(stat(path,&file_stats))
    return -1;

  *size = file_stats.st_size;
  return 0;
}

2.9如何像Shell那样在一个文件名中扩展'~'?
一个以'~'开始的文件名的标准解释是:如果单独的或者后面跟'/',那么替代当前

用户的主目录;如果跟在用户名的后面,那么替代那个用户的主目录.如果没有有效

的扩展方式被找到,那么shell将许可该文件名是一个真正的文件或者目录的名字

.
值得注意的是,不加选择的使用一个以~扩展开始的文件名会使指定文件名或者程

序变得困难;使用括号""可以防止shell上述的扩展.作为一个一般的规则,不要使

用文件名的扩展方式给程序发送命令行参数和声明环境变量(通过提示用户获得或

者从配置文件获得程序生成的文件名,是一个使用扩展较好的方法)
下面是一段C++代码(使用标准的string类)来做这个工作:
string expand_path(const string& path)
{
    if (path.length() == 0 || path[0] != '~')
      return path;

    const char *pfx = NULL;
    string::size_type pos = path.find_first_of('/');

    if (path.length() == 1 || pos == 1)
    {
        pfx = getenv("HOME");
        if (!pfx)
        {
            // Punt. We're trying to expand ~/, but HOME isn't set
            struct passwd *pw = getpwuid(getuid());
            if (pw)
              pfx = pw->pw_dir;
        }
    }
    else
    {
        string user(path,1,(pos==string::npos) ? string::npos : pos-1)

;
        struct passwd *pw = getpwnam(user.c_str());
        if (pw)
          pfx = pw->pw_dir;
    }

    // if we failed to find an expansion, return the path unchanged.

    if (!pfx)
      return path;

    string result(pfx);

    if (pos == string::npos)
      return result;

    if (result.length() == 0 || result[result.length()-1] != '/')
      result += '/';

    result += path.substr(pos+1);

    return result;
}
2.10使用命名管道(FIFOs)能做什么?
2.10.1什么是命名管道?
命名管道是一种特殊的文件,经常被用于没有联系的(没有父子关系的)进程之间传

递数据.在其他进程读的时候,一个或者多个进程写.命名管道在文件系统中是可视

的,可以被ls命令像其他文件一样被看到.命名管道也被称为fifos;意即,先进先出

.
命名管道可以被用来在没有联系的进程之间传递数据,一般的管道(匿名的)只能在

父子进程间建立连接(也不绝对,但很困难)
命名管道是严格的单向传输的,即使在支持匿名管道全双工工作的系统上.
2.10.2如何创建命名管道?
交互的创建命名管道,你将使用mknod或者mkfifo.在一些系统上,mknod在/etc里.

换句话说他可能不在你的路径里.你可以查看手册来得到细节.
在C程序里,使用mkfifo来创建命名管道:
/* set the umask explicitly, you don't know where it's been */
umask(0);
if (mkfifo("test_fifo", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP))
{
    perror("mkfifo");
    exit(1);
}
如果你没有这个函数,你将不得不使用mknod函数
/* set the umask explicitly, you don't know where it's been */
umask(0);
if (mknod("test_fifo",
            S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
           0))
{
    perror("mknod");
    exit(1);
}
2.10.3如何使用命名管道?
你可以像打开普通文件一样打开命名管道,使用read和write函数来读写他.
然而,打开管道的操作可能被阻塞,下面是一些使用规则:
.如果你以读写方式打开(O_RDWR),那么open不会阻塞.
.如果以只读方式打开,那么将阻塞到其他进程以写的方式打开,除非指定O_NONBL

OCK,那么将打开成功
.如果以只写方式打开,那么将阻塞到其他进程以读的方式打开,除非指定O_NONBL

OCK,那么将打开失败

当对FIFO读写的时候,有像pipes和套接字同样的考虑,read()将在所有写的进程关

闭的时候返回EOF, write()将在没有读进程产生SIGPIPE信号.如果SIGPIPE被阻塞

或者忽略,调用将失败--EPIPE.
2.10.4能在网络文件系统上使用命名管道吗?
不能.在网络文件系统协议上实现命名管道是很困难的.(你可以使用挂接的网络文

件系统上创建命名管道,在同一个客户的进程之间通讯)
2.10.5 多个进程可以同时写管道么?
如果写向管道的每片数据都小于PIPE_BUF的长度,那么他们将不被交叉存取.然而

,写的边界并不被保护,那么,当你从管道中读数据时,将返回尽可能多的数据,即使

他们是由多个进程写的.
PIPE_BUF的值在POSIX中至少为512.他可能也可能没有定义在limits.h中,但是他

可以被单独的管道通过pathconf()或者fpathconf请求得到.
2.10.6在应用中使用命名管道
我如何实现在服务器和多个客户之间双向通信?
超过一个的客户与服务器通讯是可能的,只要每个发向服务器的命令小于PIPE_BU

F,他们可以通过相同的命名管道向服务器发送数据.所有的客户能够很容易的知道

服务器接收的fifo.
然而,服务器不能用单一的管道与多个客户通讯.如果超过一个客户从相同的管道

重读取数据,没有任何方法保证客户得到是正确反馈.
一个可行的方案是每个客户在向服务器发送数据之前都创建他们自己的接收管道

,或者让服务器在向客户发送数据之前为每个客户创建一个发送的管道.
采用的管道名包含客户进程ID是通常标识他们的办法.在使用这种风格的管道名称

时,每次客户向服务器发送命令,他可以在命令中包含自己的进程ID.返回的数据可

以通过适当的命名管道发送.


--
                                           _
   O           @___       G               : \  
  /|__       /|/         /\|\             :  \
 /|/_       / /\         \ X_             :   \
  /  |     __/  \          | \      0     :    \
 /    0        0|          /              :     \

※ 修改:.tengel 于 Jun 13 12:02:06 修改本文.[FROM: 210.14.224.186]
※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 210.14.224.186]

[关闭][返回]