2009-08-16 72 views
2

我正在使用growisofs來通過我的Python應用程序來刻錄iso。我在兩個不同的文件中有兩個類。 GUI()(main.py)和Boxblaze()(core.py)。 GUI()構建窗口並處理所有事件和事物,而Boxblaze()具有GUI()調用的所有方法。subprocess.call管道輸出到進度條

現在,當用戶選擇了設備與燃燒,並要刻錄的文件,我需要調用調用以下命令的方法:`

growisofs -use-the-force-luke=dao -use-the-force-luke=break:1913760 -dvd-compat -speed=2 -Z /burner/device=/full/path/to.iso 

這個命令應該給類似的輸出對此:

Executing 'builtin_dd if=/home/nevon/games/Xbox 360 isos/The Godfather 2/alls-tgod2.iso of=/dev/scd0 obs=32k seek=0' 
/dev/scd0: "Current Write Speed" is 2.5x1352KBps. 
#more of the lines below, indicating progress. 
7798128640/7835492352 (99.5%) @3.8x, remaining 0:06 RBU 100.0% UBU 99.8% 
7815495680/7835492352 (99.7%) @3.8x, remaining 0:03 RBU 59.7% UBU 99.8% 
7832862720/7835492352 (100.0%) @3.8x, remaining 0:00 RBU 7.9% UBU 99.8% 
builtin_dd: 3825936*2KB out @ average 3.9x1352KBps 
/dev/burner: flushing cache 
/dev/burner: closing track 
/dev/burner: closing disc 

此命令在Boxblaze()中的名爲burn()的方法中運行。它看起來簡直像這樣:

def burn(self, file, device): 
    subprocess.call(["growisofs", '-dry-run', "-use-the-force-luke=dao", "-use-the-force-luke=break:1913760", "-dvd-compat", "-speed=2", "-Z", device +'='+ file]) 

現在我的問題有以下幾點:

  1. 我怎樣才能從輸出(括號內百分比)的進展,並有我的進度條設定「跟隨」那個進展?我的進度條是所謂的GUI()類,因爲這樣的:

    GET = builder.get_object

    self.progress_window = GET( 「progressWindow」)

    self.progressbar = GET(「進度「)

  2. 我必須在單獨的線程中運行此命令才能使GUI保持響應(以便我可以更新進度欄並允許用戶在需要時取消刻錄)?如果是這樣,我該怎麼做,仍然能夠將進度傳遞給進度條?如果你有興趣


的完整代碼,請on Launchpad。如果您已經安裝了集市,只需要運行:

bzr branch lp:boxblaze 

哦,如果你想知道,這個應用程序只能在Linux下工作 - 所以不要擔心跨平臺的兼容性。

回答

1

要獲得輸出,您需要使用subprocess.Popen調用。 (stdout = subprocess.PIPE

(第二個問題)

你可能需要一個單獨的線程,除非GUI框架可以正常循環FileDescriptor的選擇。

你可以有一個後臺線程讀取管道,處理它(提取進度),傳遞給GUI線程。

## You might have to redirect stderr instead/as well 
proc = sucprocess.Popen(command,stdout=subprocess.PIPE) 
for line in proc.stdout.readlines(): 
    ## might not work - not sure about reading lines 
    ## Parse the line to extract progress 
    ## Pass progress to GUI thread 

編輯:

我怕,我不想浪費大量的CD測試它,所以我沒有運行它,但你評論它看起來像它不是將信息輸出到標準輸出,但輸入到標準錯誤。

我建議直接在命令行上運行示例命令,並將stdout和stderr重定向到不同的文件。

growisofs [options] >stdout 2>stderr 

然後,你可以計算出標準輸出和標準輸出上的哪些東西。

如果您想要的東西來自stderr,請將stdout=subprocess.PIPE更改爲stderr=subprocess.PIPE,然後查看該效果是否更好。

EDIT2:

你不使用線程正確 - 你應該啓動它 - 而不是直接運行它。

另外:

gtk.gdk.threads_init() 
threading.Thread.__init__(self) 

很奇怪 - 在初始化器調用應該是在初始化器 - 我不認爲你需要使它成爲一個GTK主題?

調用run()方法的方式,是怪異本身:

core.Burning.run(self.burning, self.filechooser.get_filename(), self.listofdevices[self.combobox.get_active()]) 

通過調用對象的實例方法:

self.burning.run(self.filechooser.get_filename(), self.listofdevices[self.combobox.get_active()]) 

(但是你應該有一個__init__()法)

在我看來,你正在嘗試跑步,然後才能走路。嘗試編寫一些簡單的線程代碼,然後運行一些簡單的代碼來運行growisofs並解析輸出,然後使用一些簡單的gtk +後臺線程代碼,然後嘗試將它們結合在一起。實際上,首先開始寫一些簡單的面向對象的代碼,以便你首先理解方法和對象。

例如您在python中創建的所有類應該是新式類,您應該從您的初始化程序調用超類初始化程序等。

+0

我不知道我已經完全明白了什麼是你的意思。這就是我一直試圖實現它(http://pastebin.com/m6b1bdff6),但它並不完全似乎工作,因爲我得到(到終端)的唯一輸出: 的/ dev/scd0:「當前寫入速度」爲2.5x1352KBps。 – 2009-08-16 13:21:17

+0

看來,我正在尋找的信息確實來自stderr。但是,現在看來我的解析不起作用,因爲所有內容都會打印到屏幕上(請參閱pastebin鏈接)。 GUI仍然凍結。 core.py→http://pastebin.com/m586398c8 main.pu→http://pastebin.com/m28658de 另請注意,您實際上可以向growisofs命令添加-dry-run標誌以嘗試它不浪費DVD。 要看到整個事情,只需要運行: 的bzr分支LP:boxblaze – 2009-08-17 06:30:34

+0

噢,對不起,我忘了,包括運行我的應用程序的輸出。那就是: http://pastebin.com/m6e55585a – 2009-08-17 06:31:40

0

您是否可以通過超時讀取子進程?我想你可以這樣做,因爲my subProcess module被用作它的設計輸入。您可以使用它來growiso.read(.1),然後解析並顯示outdata(或可能errdata)的百分比。

0

您需要從單獨的線程運行命令,並使用gobject.idle_add調用更新gui。現在你有一個類「燃燒」,但你正在使用它錯了,應該這樣來使用:

self.burning = core.Burning(self.filechooser.get_filename(), self.listofdevices[self.combobox.get_active()], self.progressbar) 
self.burning.start() 

很明顯,你將不得不修改core.Burning。 然後,你將有機會獲得進度,所以你可以做這樣的功能:

def set_progress_bar_fraction(self, fraction): 
    self.progress_bar.set_fraction(fraction) 

然後每個更新調用它是這樣的:與線程here PyGTK的gobject.idle_add(self.set_progress_bar_fraction, fraction)

更多信息。

2

您可以使用glib.io_add_watch()來監視連接到子進程對象中stdout和stderr的管道上的輸出。

proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
stdout_id = glib.io_add_watch(proc.stdout, glib.IO_IN|glib.IO_HUP, stdout_cb) 
stderr_id = glib.io_add_watch(proc.stderr, glib.IO_IN|glib.IO_HUP, stderr_cb) 

然後當回調被調用時就應該檢查的條件,並讀取從管道中的所有數據,並對其進行處理,以獲得信息來更新進度。如果應用程序緩衝io,那麼你可能不得不使用一個pty來欺騙它,認爲它連接到一個終端,所以它會一次輸出一行。