提取手机 QQ 的聊天图片

提取手机 QQ 的聊天图片

CONTENTS

图片文件位置

遇到的问题

处理过程

文件压缩导出

文件处理

不断保留之前历史的结果就是,qq 越来越臃肿,聊天历史中的图片既然难以找到或再被发出去,那么所占据的空间就是无意义的。

本文记录了将缓存的图片文件导出并根据文件头增加后缀,以便于查看和归档的过程。

图片文件位置

经过多方搜索和查找,手机 QQ 的缓存图片文件在 Android/data/.com/tencent/mobileqq/TencentMobileQQ/chatpic/chatimg中。在我的手机上,该文件夹下是三位十六进制表示的 4096 个文件夹。猜测是 QQ 将过往的缓存图片用某种哈希算法映射到了这 4096 个 Bucket 中,而子目录下的文件是没有后缀名的。

遇到的问题

/Android/data目录是被保护的目录,在系统文件管理器(MiExplorer)中是无法访问的,通过 FTP 等方式也是无法访问的;常见的文件管理工具也都被禁止直接操作这里。最后是通过 MT 管理器将此处的文件复制到这里;

缓存的图片是没有后缀名的,但是在 MT 管理器中可以预览。不难猜测图片文件的头部信息中包含了格式相关的信息(在有的地方会被称为 Magic Number),通过读取文件开头的几个字节即可判断大部分图片文件的格式。常见图片格式的文件头有:

JPEG (jpg),文件头:FFD8FF

PNG (png),文件头:89504E47

GIF (gif),文件头:47494638

Bitmap (bmp),文件头:424D

处理过程

文件压缩导出

大量小文件的复制既缓慢又繁琐,所以先将目标文件夹复制到有操作权限的位置,例如 Downloads 目录下,然后将整个文件夹压缩起来,再整体复制到 PC 上,详细操作在不同环境上可能略有不同。

文件处理

1. 文件集中

分散在多个子文件夹中不太好处理,所以将其整理在一起:

# 在目标目录下

$ mv */* ./

2. 文件后缀添加

既然知道文件格式可以从文件的最开始几个字节提取出来,简单写个程序:

package main

import (

"fmt"

"os"

"path/filepath"

"strings"

)

const (

BufferCapacity = 8

)

type MagicInfo struct {

MagicNum int64

ByteSize int

Suffix string

}

var (

magicInfos = []MagicInfo{

{0xFFD8FF, 3, ".jpg"},

{0x89504E47, 4, ".png"},

{0x47494638, 4, ".gif"},

{0x424D, 2, ".bmp"},

}

)

func main() {

if len(os.Args) <= 1 {

fmt.Println("Please input files or directorys")

return

}

for _, path := range os.Args[1:] {

info, err := os.Stat(path)

if err != nil {

fmt.Printf("%v\n", err)

break

}

if !info.IsDir() {

handleFile(path)

continue

}

entries, err := os.ReadDir(path)

if err != nil {

fmt.Printf("%v\n", err)

break

}

for _, item := range entries {

if item.IsDir() {

continue

}

handleFile(filepath.Join(path, item.Name()))

}

}

}

func handleFile(path string) error {

suffix := getSuffix(path)

if strings.HasSuffix(path, suffix) {

return nil

}

if suffix == "" {

return nil

}

return os.Rename(path, path+suffix)

}

func getSuffix(filepath string) string {

// 1.read file header

f, err := os.Open(filepath)

if err != nil {

fmt.Printf("Failed to open file %s, err: %v\n", filepath, err)

return ""

}

buffer := make([]byte, BufferCapacity)

_, err = f.Read(buffer)

if err != nil {

fmt.Printf("Failed to open file %s, err: %v\n", filepath, err)

return ""

}

// 2. compare header with magickNumbers

for _, item := range magicInfos {

if compareBytes(buffer, item.MagicNum, item.ByteSize) {

return item.Suffix

}

}

return ""

}

// compareBytes compare bytes with a big int, max compare 8 bytes

func compareBytes(target []byte, magicNumber int64, tSize int) bool {

if len(target) < tSize {

return false

}

var n int64

for i := 0; i < tSize; i++ {

n = (n << 8) | int64(target[i])

}

return n == magicNumber

}

在目标目录下执行:

$ go run cmd/main.go chatimg/chatimg/

即可给文件加上对应格式的后缀。

注:有少部分文件是以 .tmp 为后缀且没有匹配到图片格式,猜测可能是未完成或损坏的文件,但是比例很小,大约万分之几。

相关推荐

[交流]最贵的点化石是哪个
beat365手机版官方网站

[交流]最贵的点化石是哪个

🗓️ 10-10 👁️ 7197
App Store預覽
beat365手机版官方网站

App Store預覽

🗓️ 09-16 👁️ 121
转转短片《我根本不关心中国足球》,用长文案致敬球迷
beat365手机版官方网站

转转短片《我根本不关心中国足球》,用长文案致敬球迷

🗓️ 08-02 👁️ 7895
口袋网咖app
365bet正网注册

口袋网咖app

🗓️ 07-26 👁️ 8018
辐射4哪个流派好用点图解
365bet正网注册

辐射4哪个流派好用点图解

🗓️ 07-25 👁️ 3835
2025局域网聊天软件排行 5款好用的局域网聊天工具推荐
beat365手机版官方网站

2025局域网聊天软件排行 5款好用的局域网聊天工具推荐

🗓️ 07-07 👁️ 5443
8画属土的字
beat365手机版官方网站

8画属土的字

🗓️ 07-13 👁️ 4017
世界杯随想(1)         - 湾区金头脑发表于 体育看台 - 论坛
英国beat365官方登录

世界杯随想(1) - 湾区金头脑发表于 体育看台 - 论坛

🗓️ 10-04 👁️ 167
从图片扫描二维码
365bet正网注册

从图片扫描二维码

🗓️ 09-19 👁️ 3237
[Android] 优质的本地电子书阅读 eBoox v2.60 Google Play版
英国beat365官方登录

[Android] 优质的本地电子书阅读 eBoox v2.60 Google Play版

🗓️ 08-01 👁️ 2961
新技术革命的发展趋势与影响特点
英国beat365官方登录

新技术革命的发展趋势与影响特点

🗓️ 10-06 👁️ 1789
波导D3老年手机评测:专为老年人打造的实用之选
365bet正网注册

波导D3老年手机评测:专为老年人打造的实用之选

🗓️ 10-15 👁️ 9911