2015-03-11 2 views
3

мне нужно распаковать файл в именованный канал вернуть его:FIFO-файл в TCL

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 &

+0

Согласно [mkfifo руководство] (http://linux.die.net/man/3/mkfifo), такой файл должен быть открыт одновременно чтение и письмо. Это означает, что кому-то нужно прочитать данные, которые вы распаковываете в него. Кто-нибудь читает, что вы разархивируете в файл mkfifo? – Bogdan

+0

Да, он будет прочитан после вызова функции, поэтому gunzip выполняется в фоновом режиме. –

ответ

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 
} 
2

Проблема в том, что ядро ​​будет блокировать в 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 будет делать под обложками, минус некоторые флаги, которые здесь не применяются, и плюс NONBLOCK, который является магией, которую мы хотим).

+0

[Donal Fellows] (http://stackoverflow.com/users/301832/donal-fellows) Он сообщает об ошибке: не удалось открыть «/ tmp/52977»: нет такого устройства или адреса? –