断管 - 尝试在LCD显示器上显示dd进度
我正在尝试用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) 只会给你压缩后的大小,所以计算百分比的时候会出错。