【问题标题】:Broken Pipe - Trying to display progress of dd on LCD displayBroken Pipe - 试图在 LCD 显示屏上显示 dd 的进度
【发布时间】:2013-03-04 00:35:03
【问题描述】:

我正在尝试使用 Python 创建一个工具,用于使用 Raspberry Pi 对 CF 卡进行映像。

在我使用 dd 实现压缩图像之前,我大部分时间都在工作。

当我尝试将gzip 的输出通过管道传输到dd时,我失去了戳dd 进程并获得进展的能力。

我尝试使用多个子进程,但总是出现管道损坏或没有此类文件错误。

下面是我的代码:

#!/usr/bin/env python
from Adafruit_CharLCD import Adafruit_CharLCD
import os
import sys
import time
import signal
from subprocess import Popen, PIPE
lcd = Adafruit_CharLCD()
lcd.begin(16,2)
imgpth = '/home/pi/image/image_V11.img.gz'
line0 = ""
line1 = ""
q = 0
r = 0
s = 0

def lcdPrint(column, row, message, clear=False):
    if ( clear == True ):
        lcd.clear()

    lcd.setCursor(column, row)
    lcd.message(message)

lcd.clear()                 
lcdPrint(0, 0, 'Preparing Copy', True)
lcdPrint(0, 1, '')

gz = Popen(['gunzip -c /home/pi/image/image_V11.img.gz'], stdout=PIPE)
dd = Popen(['dd of=/dev/sda'],stdin=gz.stdout, stderr=PIPE)                     

filebyte = os.path.getsize(imgpth)                                  
flsz = filebyte/1024000 

while dd.poll() is None:                                        
    time.sleep(1)
    dd.send_signal(signal.SIGUSR1)
    while 1:                                            
        l = dd.stderr.readline()
    if '(' in l:                                            
        param, value = l.split('b',1)                           
        line1 = param.rstrip()                              
        r = float(line1)                                    
        s = r/1024000
        break
lcdPrint(0, 0, 'Copying....', True)
q = round(s/flsz*100, 2)                                
per = str(q)        

lcdPrint(0, 1, per + '% Complete',)

lcdPrint(0, 0, 'Copy Complete', True)   
time.sleep(1)
exit()

我该如何解决这个问题?

【问题讨论】:

  • 你能不能把gzip 的输出写到一个文件里,这样你就不用管dd 的输入了?
  • 我可以,但我受大小限制,我在 PI 中只有一个 4GB 的 SD 卡,提取的 dd 图像文件为 16GB,压缩后的图像只有 1.5GB。所以我需要能够即时解压。
  • while 1 附近的缩进错误。检查 SIGUSR1 是否不会杀死 dd(它不应该)。在dd.stderr.readline() 失败后dd.poll() 返回什么?
  • 代码中的缩进是正确的(只是没有正确发布,仍在学习这一点) dd.pol() 和 dd.stderr() 不返回任何内容,因为代码失败dd 作为子进程的开放。
  • 使用['dd', 'of=/dev/sda'] 代替['dd of=/dev/sda']gunzip 相同)

标签: python gzip subprocess dd


【解决方案1】:

我偶然发现了这个问题,因为我正在做同样的事情。我的完整解决方案在这里:

我试图找出我所拥有的和你所拥有的之间的一些差异,这些差异可能会向你展示解决方案。

在启动 dd 时,我将 stderr 和 stdout 都重定向到了管道。

dd = subprocess.Popen(['dd', 'of=/dev/sda', 'bs=1M'], bufsize=1, stdin=unzip.stdout, stdout=PIPE, stderr=STDOUT)

我不认为这真的应该有所作为。你需要的一切都应该去 stderr 但由于某种原因它似乎对我来说很混乱。

我使用单独的线程从 dd 获取输出:

def read_pipe(out, queue):
    for line in iter(out.readline, b''):
        queue.put(str(line))
    out.close()

dd_queue = queue.Queue()
dd_thread = threading.Thread(target = read_pipe, args=(dd.stdout, dd_queue))
dd_thread.daemon = True
dd_thread.start()

然后当你打电话时:

dd.send_signal(signal.SIGUSR1)

输出被 dd_queue 捕获。

我还发现gzip压缩文件的未压缩大小存储在最后4个字节中:

fl = open(str(imgpath), 'rb')
fl.seek(-4, 2)
r = fl.read()
fl.close()
size = struct.unpack('<I', r)[0]

os.path.getsize(imgpth) 只会给你压缩后的大小,所以百分比计算会出错。

【讨论】:

    猜你喜欢
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多