断管 - 尝试在LCD显示器上显示dd进度

1 投票
1 回答
861 浏览
提问于 2025-04-17 17:48

我正在尝试用Python创建一个工具,用树莓派来制作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()

我该怎么解决这个问题呢?

1 个回答

0

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

我试着找出我和你的代码之间的一些不同之处,希望能帮你找到解决办法。

在启动dd命令时,我把错误输出和正常输出都重定向到了管道中。

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

我觉得这样做其实没什么大区别。你需要的所有信息应该都在错误输出中,但不知道为什么对我来说似乎有点混乱。

我使用了一个单独的线程来获取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中。

我还发现,gzipped文件的未压缩大小存储在最后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) 只会给你压缩后的大小,所以计算百分比的时候会出错。

撰写回答