有没有一种快速的方法来读取dd

时间:2019-04-24 18:58:13

标签: shell sh busybox dd

我试图在循环中使用dd读取二进制文件中的每对其他字节,但是这太慢了。

我在BusyBox嵌入式设备上有一个二进制文件,其中包含rgb565格式的数据。每个像素为2个字节,我正尝试读取其他每个像素以进行非常基本的图像缩放,以减小文件大小。

整体大小为640x480,通过将dd循环到960字节块大小,我已经能够读取每隔一个“行”像素。但是,即使在我的本地系统上,通过循环2字节的块大小对剩下的所有其他“列”执行相同的操作也是非常慢的

i=1
while [[ $i -le 307200 ]]
do
        dd bs=2 skip=$((i-1)) seek=$((i-1)) count=1 if=./tmpfile >> ./outfile 2>/dev/null
        let i=i+2
done

当我得到期望的输出时,此方法不可用。

是否有一些不太明显的方法让dd快速复制每隔一对字节?

可悲的是,对于在BusyBox中编译的内容,我没有太多控制权。我欢迎其他可能的方法,但我可以使用dd / sh解决方案。例如,一个构建省略了head -c ...

感谢所有反馈。我将检查各种建议,然后再返回结果。

3 个答案:

答案 0 :(得分:3)

对于不需要使用换行符和空字节的sed或awk之类的工具,跳过其他所有字符都是微不足道的。但是Busybox对sed和awk中的空字节的支持很差,以至于我认为您根本无法应付。可以处理换行符,但这是一个巨大的痛苦,因为根据4字节块中的每个位置是否换行,有16种不同的组合要处理。

由于任意二进制数据很麻烦,所以我们将其转换为十六进制或八进制!我将从bin2hex and hex2bin scripts by Stéphane Chazelas中汲取灵感。由于我们不在乎中间格式,因此我将使用八进制,因为它的最后一步使用了仅支持八进制的printf,因此使用八进制更为简单。 Stéphane的hex2bin使用awk进行十六进制到八进制的转换; oct2bin可以使用sed。因此,最后您需要 shodsedprintf 。 我认为您无法避免使用printf:输出空字节至关重要。尽管od是必不可少的,但大多数选项不是必需的,因此应该可以对该代码进行调整,以支持精简的od并进行更多的后处理。

od -An -v -t o1 -w4 |
sed 's/^ \([0-7]*\) \([0-7]*\).*/printf \\\\\1\\\\\2/' |
sh

与基于dd的方法相比,它之所以如此之快,是因为BusyBox在父进程中运行printf,而dd需要它自己的进程。分叉很慢。如果我没记错的话,有一个编译选项可以使BusyBox分叉成为所有实用程序。在这种情况下,我的方法可能会和您一样慢。这是使用dd的一种中间方法,它无法避免产生分叉,但至少避免每次都打开和关闭文件。它应该比您的快一点。

i=$(($(wc -c <"$1") / 4))
exec <"$1"
dd ibs=2 count=1 conv=notrunc 2>/dev/null
while [ $i -gt 1 ]; do
  dd ibs=2 count=1 skip=1 conv=notrunc 2>/dev/null
  i=$((i - 1))
done

答案 1 :(得分:1)

不知道使用BusyBox是否会更快甚至可能,但这是一个想法...

#!/bin/bash

# Empty result file
> result

exec 3< datafile
while true; do
    # Read 2 bytes into file "short"
    dd bs=2 count=1 <&3 > short 2> /dev/null
    [ ! -s short ] && break
    # Accumulate result file
    cat short >> result
    # Read two bytes and discard
    dd bs=2 count=1 <&3 > short 2> /dev/null
    [ ! -s short ] && break
done

或者这应该更有效:

#!/bin/bash

exec 3< datafile
for ((i=0;i<76800;i++)) ; do
    # Skip 2 bytes then read 2 bytes
    dd bs=2 count=1 skip=1 <&3 2> /dev/null
done > result

或者,也许您可​​以使用netcatssh使用适当的工具将文件发送到明智(功能更强大)的计算机上,以处理并返回文件。例如,如果远程计算机具有 ImageMagick ,则可以非常简单地缩小图像的比例。

答案 2 :(得分:0)

另一种选择是使用 Lua ,它以体积小,速度快并且非常适合嵌入式系统而著称-请参见Lua website。也有预构建的,可下载的二进制文件。也建议在Busybox website here上使用。

我以前从未写过任何Lua,所以可能效率不高,但这似乎工作得很好,并且可以在几毫秒内在桌面上处理640x480 RGB565图像。

magick -depth 16 -size 640x480 gradient: gray:image.bin

我使用 ImageMagick 创建了灰度测试图像,如下所示:

lua scale.lua image.bin smaller.bin

然后我使用以下命令运行上述Lua脚本:

magick -depth 16 -size 320x240 gray:smaller.bin smaller.jpg

然后我制作了JPEG,可以通过以下方式查看进行测试:

image: samueldebruyn/debian-git

pipelines:
  default:
    - step:
        script:
          - echo "Pipeline Init"
          - apt-get update
          - apt-get -qq install git-ftp
          - git ftp init --user $FTP_USERNAME --passwd $FTP_PASSWORD ftp://$FTP_HOST