4

我需要在命名管道中解压缩文件返回它:

proc unzip_file_if_needed { fileName } {
    if { [file extension $fileName] != ".gz" } {
        return $fileName;
    }
    set tmpDir [fileutil::tempdir]
    set tmpFileName [ file join $tmpDir [ pid ] ]
    if { [file exists $tmpFileName ] } {
        file delete $tmpFileName
    }
    exec mkfifo $tmpFileName
    exec gunzip -c $fileName > $tmpFileName &
    return $tmpFileName
}

它挂在 exec gunzip -c $fileName > $tmpFileName &

4

2 回答 2

3

问题是内核将阻塞open()系统调用,直到打开相反方向的 fifo,并且 Tcl 在分叉之前在父进程中创建重定向(因为这在正常情况下允许更可靠的错误处理)。您需要O_NONBLOCK标志传递给open()系统调用,但该exec命令无法让您控制它。所以需要一些技巧!

set fd [open $tmpFileName {WRONLY NONBLOCK}]
exec gunzip -c $fileName >@$fd &
close $fd

这是open通过手动使用我们想要的标志(Tcl 将它们映射到没有O_前缀的)然后将该描述符传递给子进程来实现的。请注意,由于这是我们正在设置的管道的写入端,我们必须以WRONLY模式打开(这是在幕后open … w做的事情,减去一些在这里不适用的标志,再加上NONBLOCKwhich是我们想要的魔法)。

于 2015-03-11T13:34:51.767 回答
0

我以这种方式解决了这个问题:

proc unzip_file_if_needed { fileName } {
    if { [file extension $fileName] != ".gz" } {
        return $fileName;
    }
    set tmpDir [fileutil::tempdir]
    set pId [pid]
    set tmpFileName [ file join $tmpDir pId ]
    set unzipCmd [ file join $tmpDir [ append pId "cmd.sh" ] ]
    if { [file exists $tmpFileName ] } {
        file delete $tmpFileName
    }

    if { [file exists $unzipCmd ] } {
        file delete $unzipCmd
    }

    set cmdDesc [open $unzipCmd { CREAT EXCL RDWR} 0777]
    puts $cmdDesc "\#!\/bin\/bash\n gunzip -c \$1 > \$2"
    close $cmdDesc

    exec mkfifo $tmpFileName
    exec $unzipCmd $fileName $tmpFileName >&@1 &

    return $tmpFileName
}
于 2015-03-13T09:34:37.997 回答