ysb20220528 2023-01-27 16:31 采纳率: 0%
浏览 26

问题:该怎么解决通过subprocess.Popen()获取手机图片数据时出现数据失真现象

我想尝试编写代码以将手机中的图片大量传输到电脑中。我尝试了使用adb shell su pull命令直接将大量图片拷贝到指定文件夹,但因获取不到root权限而失败。因此,我转而通过adb shell cat获取图片数据,然后通过with open as在指定文件夹生成对应文件名并写入到其中。尽管传输过程非常顺利,没有报任何错误,但传输结束后却发现拷贝的所有图片失真,有的甚至打不开。挑选了几张图片进行排查,发现所有拷贝后的图片大小比原图小,其中jpg小了大概17B左右,png格式的图片少了35B左右。下面是编写的用于复制手机图片的代码。我使用过该代码(当然某些地方要适当改改)复制过本机图片和MuMu模拟器的图片,都没有发现失真的问题,仅在复制手机图片时发生了图片失真,所以我想请问一下大能们问题出在哪里。

from subprocess import Popen, PIPE
import threading


class CopyFiles:
    """将目标文件夹下的所有文件拷贝到另一文件夹"""
    """拷贝手机数据时,请先使用adb devices获取手机序列号,确保手机已成功连接"""

    def get_all_files_name(self):
        """获取目标文件夹下所有文件的文件名"""
        p = Popen(f'{self.adb} -s {self.serial_num} shell ls sdcard/{self.target_dir}',
                  shell=True, stdout=PIPE, encoding='utf-8')
        result = p.communicate()[0].strip()
        times = result.count('\n')
        for i in range(times + 1):
            self.file_name_list.append(result.split('\n')[i])

    def __init__(self, serial_num: str, target_dir: str, copy_addr: str):
        self.adb = 'F:/android_sdk/platform-tools/adb.exe'
        self.serial_num = serial_num
        self.target_dir = target_dir
        self.copy_addr = copy_addr
        self.file_name_list = []
        self.get_all_files_name()
        self.files_dict = {}
        self.loop = True
        self.execution_time = 0

    def read_files(self):
        """读取图片文件"""
        # todo 实际传输过程中发现图片失真,对比copy图片和原图发现,copy图片大小要小于原图
        for file_name in self.file_name_list:
            p = Popen(f'{self.adb} -s {self.serial_num} shell cat sdcard/{self.target_dir}/{file_name}', shell=True, stdout=PIPE)
            content = p.communicate()[0].strip()
            with open('E:/picture/sss/test1.txt', 'wb') as f1:
                f1.write(content)  # 1431,505 - 1428,537: 比原图多2,968 B
            content = content.replace(b'\r\n', b'\n').replace(b'\r\n', b'\n')
            with open('E:/picture/sss/test2.txt', 'wb') as f2:
                f2.write(content)  # 1428,518 - 1428,537: 比原图少19 B
            self.files_dict[file_name] = content
        self.loop = False

    def write_files(self):
        """写入图片文件"""
        while True:
            if len(self.files_dict) > 0:
                for file_name in list(self.files_dict.keys()):
                    # 这里需将self.files_dict.keys()转换为列表,
                    # 否则会报RuntimeError: dictionary changed size during iteration错误
                    with open(self.copy_addr + '/' + file_name, 'wb') as f:
                        f.write(self.files_dict.get(file_name))
                    self.files_dict.pop(file_name)
                    self.execution_time += 1
            if not self.loop and len(self.files_dict) == 0:
                break


if __name__ == '__main__':
    copy_file = CopyFiles('手机序列号', 'Pictures/test', 'E:/picture/sss')
    read_thread = threading.Thread(target=copy_file.read_files)
    write_thread = threading.Thread(target=copy_file.write_files)
    read_thread.start()
    write_thread.start()
    while True:
        if not read_thread.is_alive() and not write_thread.is_alive():
            print(f'execution times: {copy_file.execution_time}')
            break

  • 写回答

1条回答 默认 最新

  • 快撑死的鱼 2023-01-27 23:52
    关注

    回答不易,求求您采纳点赞哦

    您可能是使用了错误的文件读写模式或编码方式导致图片失真。在读取图片数据时,应使用二进制模式“rb”打开文件,在写入文件时使用“wb”模式。

    还有一种可能是文件在读取和写入时编码不一致导致的,可以尝试指定编码格式。

    为了确保文件正确读取和写入,您可能需要进行错误处理和异常处理。

    贴上示例代码

    import subprocess
    
    with open('path_to_save_image', 'wb') as img_file:
        subprocess.Popen(['adb', 'shell', 'cat', '/path/to/image.jpg'],stdout=img_file)
    

    上面这段代码是在打开一个文件,并使用subprocess.Popen()从手机中读取文件并将其写入到电脑上。记得将path_to_save_image和/path/to/image.jpg替换成正确的路径。

    评论

报告相同问题?

问题事件

  • 创建了问题 1月27日

悬赏问题

  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?