如何用Python读取Java(Android)写入的short/int数组文件
问题背景
我在Android(Java)环境下有两个大型数组,一个是short类型,另一个是int类型,想要把它们写入文件后,在Python中读取并还原成原数组。我原本以为Java侧的写入操作没问题,但Python这边始终无法正确解析文件,求指点怎么解决这个问题。
我的Java写入代码有两种尝试:
Java侧写入代码
方式一:用ObjectOutputStream序列化对象
File mFile = new File( this.getExternalFilesDir(null),"testFile.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(mFile)); objectOutputStream.writeObject(intArray); objectOutputStream.close();
方式二:循环用OutputStream.write写入
File mFile = new File( this.getExternalFilesDir(null),"testFile.txt"); OutputStream outputStream = new FileOutputStream(mFile); for (int x: intArray) { outputStream.write(x); } objectOutputStream.close(); // 这里还有个笔误,应该是outputStream.close()
我尝试用Python的struct库读取,但代码抛出错误:error: unpack requires a buffer of 104 bytes,我的Python代码如下:
with open('/../testFile.txt') as mFile: for ln in mFile: print( list( struct.unpack('I*'(len(ln)//4), ln) ) )
问题分析&解决方案
咱们先把问题拆解清楚:你的Java写入方式其实都存在问题,这才是Python读不对的根源,然后再对应给出正确的读写方案。
1. Java写入的问题在哪?
- 方式一的坑:
ObjectOutputStream是Java专属的对象序列化工具,它写入的不是数组的原始二进制数据,而是包含了Java对象元数据的序列化格式(比如对象类型标识、长度信息等),Python的struct库根本无法解析这种格式,所以肯定读不出来。 - 方式二的坑:
OutputStream.write(int)方法只会写入这个int值的最低8位(一个字节),而Java的int是4字节的,这样写会直接丢掉高24位的数据,导致数组内容完全损坏。比如你测试的1000,二进制是00000000 00000000 00000011 11101000,用write(x)只会写入最后一个字节11101000(对应十进制232),数据完全变了。
2. 正确的Java写入方式
要让Python能正确读取,Java必须把数组写成原始的二进制字节流,每个元素按固定字节数写入(int占4字节,short占2字节),推荐用DataOutputStream,它专门用来写入Java基本数据类型的二进制值:
写入int数组
File mFile = new File(this.getExternalFilesDir(null), "int_array.bin"); try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(mFile))) { // 先写入数组长度,方便Python读取时知道要读多少个元素 dos.writeInt(intArray.length); for (int num : intArray) { dos.writeInt(num); // 每个int写4字节,默认大端字节序 } } catch (IOException e) { e.printStackTrace(); }
写入short数组
File mFile = new File(this.getExternalFilesDir(null), "short_array.bin"); try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(mFile))) { // 用int存储数组长度,避免short的范围限制(如果数组很大的话) dos.writeInt(shortArray.length); for (short num : shortArray) { dos.writeShort(num); // 每个short写2字节,默认大端字节序 } } catch (IOException e) { e.printStackTrace(); }
3. 对应的Python读取代码
注意要以二进制模式打开文件(rb),因为我们写的是二进制数据,不是文本。另外Java默认用大端字节序(big-endian),所以Python的struct格式符要加前缀>指定字节序。
读取int数组
import struct # 替换成你的文件实际路径 with open('/storage/emulated/0/Android/data/[你的包名]/files/int_array.bin', 'rb') as f: # 先读取数组长度(4字节的int) length_bytes = f.read(4) array_length = struct.unpack('>I', length_bytes)[0] # 读取所有int元素的二进制数据,每个占4字节 int_bytes = f.read(array_length * 4) # 解析成int数组 int_array = list(struct.unpack(f'>{array_length}I', int_bytes)) print("还原的int数组:", int_array)
读取short数组
import struct with open('/storage/emulated/0/Android/data/[你的包名]/files/short_array.bin', 'rb') as f: length_bytes = f.read(4) array_length = struct.unpack('>I', length_bytes)[0] short_bytes = f.read(array_length * 2) # 格式符h对应short类型,>指定大端字节序 short_array = list(struct.unpack(f'>{array_length}h', short_bytes)) print("还原的short数组:", short_array)
4. 你之前Python代码的错误点
- 没有用二进制模式打开文件:
open('/../testFile.txt')默认是文本模式,会把二进制数据当成文本处理,导致数据截断或乱码,必须加rb。 - 循环读取“行”:二进制文件没有文本文件的“行”概念,这样读取会把连续的二进制数据拆成错误的块。
- 格式符语法错误:
'I*'(len(ln)//4)是错误的写法,应该用动态格式字符串,比如f'>{count}I'来指定要解析的元素数量。
内容的提问来源于stack exchange,提问作者Shyam
相关产品推荐
相关产品推荐

