上一篇文章写到的权限检查脚本,后来我又加入了 apk size 对比的功能,分享给组内同事使用后,暴露出一个问题:脚本输出的 apk size 和 Jenkins 出包信息以及电脑上显示的存储大小都有差异。那么,以何为准呢?
以下是同事的提问及我的回复(已过滤敏感信息):
使用脚本发现 APK SIZE 的检测结果,与在 Jenkins 出包信息有差异,且差异不小。
电脑上显示的存储大小也有差异,具体截图如下:
1、使用脚本检查两个版本结果为:
脚本中计算 apk size 的命令是:ls -s -k
ls -- list directory contents
-s Display the number of file system blocks actually used by each
file, in units of 512 bytes, where partial units are rounded up
to the next integer value. If the output is to a terminal, a
total sum for all the file sizes is output on a line before the
listing. The environment variable BLOCKSIZE overrides the unit
size of 512 bytes.
-k If the -s option is specified, print the file size allocation in
kilobytes, not blocks. This option overrides the environment
variable BLOCKSIZE.
如上所示,这个命令的作用是显示每个文件实际占有的文件系统中块(Block)的数量,每个块的大小是 512 字节。
确实,这个命令输出的信息有问题,在新脚本中已更正。具体的解释见第2&3条回复。
2、查看 Jenkins 出包信息,大小差异为 0.25M:
Jenkins 计算 apk size 的命令是:du -k
du -- display disk usage statistics
-k Display block counts in 1024-byte (1-Kbyte) blocks.
du 是 Linux 系统中查看磁盘使用空间的命令,输出的是文件占有系统磁盘空间的块的数量(和上面提到的 ls -s 功能一样),加上参数 -k 可将块的数量转换成 1024 字节(1KB)的形式输出。
本来我最早写 apk size 对比的脚本时也打算用 du -k 的命令,结果发现这个命令在不同系统中会因为块的大小和文件占有磁盘空间大小的不同导致显示的 apk size 大小有差异。
后来转用了 ls -s -k 命令,结果发现,ls -s -k 踏入的是同样的坑(在不同系统中会因为块的大小和文件占有磁盘空间大小的不同导致显示的 apk size 大小有差异)。
说到这里,不得不提一下文件大小的两个概念:
(1)文件占用磁盘空间的大小
(2)文件实际的大小
du -k 和 ls -s -k 属于第一种,计算的都是文件占用磁盘空间的大小。在电脑的文件系统中,存储是以块(Block)为单位的,不同的系统块的大小不一样,比如说 macOS 一个块的大小是 4096 字节。假设一个文件有 4097 字节,4097-4096=1,这个文件在占用了一个块之后,还有一个字节会占用到一个块,而块与块之间是不共享空间的,也就是说,剩下的 1 字节占用了一个块,这个块还空出 4095 字节,但是无法用于存储其他文件。所以,这个大小为 4097 字节的文件占用了 2 个块。而 du -k 和 ls -s -k 计算的正是每个文件占用块的多少。同理可得,其中必定有部分块是没有占满的,所以和实际的文件大小有差异。
那么,如何获得文件实际的大小呢?请看第三条回复
3、查看电脑中存储信息,V122 出现了两个大小的值:
截图中,“通用”条目下的“大小”一行,15538958 字节表示的正是文件实际的大小。而括号中的“磁盘上的 16.4MB”,网上查到有人说是“压缩数据真正需要多少存储空间”(http://www.kbase101.com/question/47039.html),无法判断真假。
文件名右边的“15.5MB”,其实是 15538958bytes/1000/1000=15.538958MB,约等于 15.5MB。
文件的实际大小,可通过 ls -l 获得:
新的脚本已更新为获取文件的实际大小。
脚本如下:
#!/usr/bin/env bash
#清空上次运行后产生的文件
if [[ -f permission_old.txt ]]; then
rm permission_old.txt permission_new.txt
fi
#读取apk文件地址
read -p "请输入上个版本apk文件存放地址:" apk_old
read -p "请输入最新版本apk文件存放地址:" apk_new
#检查apk size
b_size_old=`ls -l ${apk_old} | awk '{print $5}'`
k_size_old=`awk 'BEGIN{printf "%.2f
", "'${b_size_old}'"/'1024'}'`
m_size_old=`awk 'BEGIN{printf "%.2f
", "'${k_size_old}'"/'1024'}'`
b_size_new=`ls -l ${apk_new} | awk '{print $5}'`
k_size_new=`awk 'BEGIN{printf "%.2f
", "'${b_size_new}'"/'1024'}'`
m_size_new=`awk 'BEGIN{printf "%.2f
", "'${k_size_new}'"/'1024'}'`
#aapt命令解析apk,输出权限到文件
aapt d badging ${apk_old} | grep "uses-permission:" | awk -F "'" '{print $2}' > permission_old.txt
aapt d badging ${apk_new} | grep "uses-permission:" | awk -F "'" '{print $2}' > permission_new.txt
#遍历新版本权限列表,对比旧版本权限列表是否相同,不同则为新增
for x in $(cat permission_new.txt); do
if cat permission_old.txt | grep ${x} > /dev/null; then
echo "hello, world" > /dev/null
else
echo ${x} >> permission_increase.txt
fi
done
#遍历旧版本权限列表,对比新版本权限列表是否相同,不同则为新减少
for y in $(cat permission_old.txt); do
if cat permission_new.txt | grep ${y} > /dev/null; then
echo "hello, world" > /dev/null
else
echo ${y} >> permission_decrease.txt
fi
done
#判断permission_increase.txt是否存在:存在,输出新增权限提醒;不存在,输出无新增权限
if [[ ! -f permission_increase.txt ]]; then
echo "无新增权限"
else
echo "新增权限:"
cat permission_increase.txt
#删除新增权限文件
rm permission_increase.txt
fi
#判断permission_decrease.txt是否存在:存在,输出新减少权限提醒;不存在,输出无新减少权限
if [[ ! -f permission_decrease.txt ]]; then
echo "无新减少权限"
else
echo "新减少权限:"
cat permission_decrease.txt
#删除新减少权限文件
rm permission_decrease.txt
fi
#输出apk size
echo "------"
echo "上个版本apk size: ${m_size_old}MB(${k_size_old}KB)"
echo "最新版本apk size: ${m_size_new}MB(${k_size_new}KB)"
#对比两个版本的apk size大小变化
if [[ `echo "${m_size_new} > ${m_size_old}" | bc` -eq 1 ]]
then
exceeded_size=$(printf "%.2f" `echo "scale=2;${m_size_new}-${m_size_old}"|bc`)
echo "最新版本比上个版本增加${exceeded_size}MB"
else
echo "apk size未增加"
fi
欢迎关注微信公众号"测试开发Stack"