带有二进制数据的python文件I/O

带有二进制数据的python文件I/O,python,file-io,jpeg,bitstring,Python,File Io,Jpeg,Bitstring,我正在从mp3数据中提取jpeg类型的比特,实际上这将是专辑艺术。 我曾考虑使用名为诱变剂的库,但我想尝试使用bits进行一些练习 import os import sys import re f = open(sys.argv[1], "rb") #sys.argv[1] gets mp3 file name ex) test1.mp3 saver = "" for value in f: for i in value: hexval = hex(ord(i))[2

我正在从mp3数据中提取jpeg类型的比特,实际上这将是专辑艺术。 我曾考虑使用名为诱变剂的库,但我想尝试使用bits进行一些练习

import os
import sys
import re

f = open(sys.argv[1], "rb")
#sys.argv[1] gets mp3 file name ex) test1.mp3

saver = ""
for value in f:
    for i in value:
        hexval = hex(ord(i))[2:]
        if (ord(i) == 0):
            saver += "00" #to match with hex form
        else:
            saver += hexval


header = "ffd8"
tail = "ffd9"
这部分代码是以位形式获取mp3,然后将其转换为十六进制 并查找以ffd8开头,以ffd9结尾的jpeg预告片

frontmatch = re.search(header,saver)
endmatch = re.search(tail, saver)
startIndex = frontmatch.start()
endIndex = endmatch.end()

jpgcontents = saver[startIndex:endIndex]
scale = 16 # equals to hexadecimal
numbits = len(jpgcontents) * 4 #log2(scale)
bitcontents = bin(int(jpgcontents, scale))[2:].zfill(numbits)
在这里,我得到头部和尾部之间的位,并将其转换为 二进制形式。应该是mp3文件的jpg部分

txtfile = open(sys.argv[1] + "_tr.jpg", "w")
txtfile.write(bitcontents)
我将bin写入新文件,写入类型为jpg。 很抱歉,我将其命名为txtfile

但是这些代码给出的错误是

Error interpreting JPEG image file
(Not a JPEG file: starts with 0x31 0x31)
我不确定我提取的位是错误的还是写入了文件 这一步是错误的。或者代码中可能存在其他问题

我使用的是linux版本的python 2.6。有什么问题吗
只需将str类型的bin数据写入JPG?

您需要将其写入二进制文件

尝试:


你需要把它写成二进制

尝试:


您正在创建一个ASCII 0和1字符串,即\x30和\x31,但JPEG文件必须是正确的二进制数据。因此,如果您的文件应该有一个单字节,例如\xd8,那么您应该有这八个字节:11011000或\x31\x31\x30\x31\x31\x30\x30

你不需要做那些乱七八糟的转换工作。您可以直接搜索所需的字节模式,使用十六进制转义序列写入它们。您甚至不需要正则表达式:简单的string.index或.find方法可以轻松快速地完成这项工作

with open(fname, 'rb') as f:
    data = f.read()

header = "\xff\xd8"
tail = "\xff\xd9"

try:
    start = data.index(header)
    end = data.index(tail, start) + 2
except ValueError:
    print "Can't find JPEG data!"
    exit()

print 'Start: %d End: %d Size: %d' % (start, end, end - start)

with open(fname + "_tr.jpg", 'wb') as f:
    f.write(data[start:end])
在Python2.6.6上测试

然而,像这样提取嵌入式JPEG数据并不是万无一失的,因为这些头和尾字节序列可能存在于MP3声音数据中

FWIW,将二进制数据转换为十六进制字符串并返回的一种更简单的方法是使用模块中的hexlify和unhexlify

下面是使用和不使用binascii函数进行这些转换的一些示例

from binascii import hexlify, unhexlify

#Create a string of all possible byte values
allbytes = ''.join([chr(i) for i in xrange(256)])
print 'allbytes'
print repr(allbytes)

print '\nhex list'
print [hex(ord(v))[2:].zfill(2) for v in allbytes]
hexstr = hexlify(allbytes)

print '\nhex string'
print hexstr
newbytes = ''.join([chr(int(hexstr[i:i+2], 16)) for i in xrange(0, len(hexstr), 2)])

print '\nNew bytes'
print repr(newbytes)

print '\nUsing unhexlify'
print repr(unhexlify(hexstr))    
输出


请注意,除了将print语句转换为print函数调用之外,此代码还需要一些修改才能在Python 3上运行,因为普通Python 3字符串是Unicode字符串,而不是字节字符串。

您正在创建一个ASCII 0和1字符串,即.\x30和\x31,但JPEG文件需要是正确的二进制数据。因此,如果您的文件应该有一个单字节,例如\xd8,那么您应该有这八个字节:11011000或\x31\x31\x30\x31\x31\x30\x30

你不需要做那些乱七八糟的转换工作。您可以直接搜索所需的字节模式,使用十六进制转义序列写入它们。您甚至不需要正则表达式:简单的string.index或.find方法可以轻松快速地完成这项工作

with open(fname, 'rb') as f:
    data = f.read()

header = "\xff\xd8"
tail = "\xff\xd9"

try:
    start = data.index(header)
    end = data.index(tail, start) + 2
except ValueError:
    print "Can't find JPEG data!"
    exit()

print 'Start: %d End: %d Size: %d' % (start, end, end - start)

with open(fname + "_tr.jpg", 'wb') as f:
    f.write(data[start:end])
在Python2.6.6上测试

然而,像这样提取嵌入式JPEG数据并不是万无一失的,因为这些头和尾字节序列可能存在于MP3声音数据中

FWIW,将二进制数据转换为十六进制字符串并返回的一种更简单的方法是使用模块中的hexlify和unhexlify

下面是使用和不使用binascii函数进行这些转换的一些示例

from binascii import hexlify, unhexlify

#Create a string of all possible byte values
allbytes = ''.join([chr(i) for i in xrange(256)])
print 'allbytes'
print repr(allbytes)

print '\nhex list'
print [hex(ord(v))[2:].zfill(2) for v in allbytes]
hexstr = hexlify(allbytes)

print '\nhex string'
print hexstr
newbytes = ''.join([chr(int(hexstr[i:i+2], 16)) for i in xrange(0, len(hexstr), 2)])

print '\nNew bytes'
print repr(newbytes)

print '\nUsing unhexlify'
print repr(unhexlify(hexstr))    
输出


请注意,除了将print语句转换为print函数调用之外,此代码还需要进行一些修改才能在Python 3上运行,因为纯Python 3字符串是Unicode字符串,而不是字节字符串。

Oups,您没有完成预期的操作。bin生成一个字符串,其中包含二进制形式的值。如果输入文件中的内容是:

saver是一个文本形式的十六进制字符字符串,类似于初始字符串132ABC的313233414243 jpgcontents的格式相同,以ffd8开头,以ffd9结尾 然后应用神奇的公式binintjpgcontents,scale[2:] 将十六进制字符串转换为长整数 将长整数转换为二进制表示字符串-此部分将转换整数255中的hexa ff,并以字符串0b11111111结尾 如果需要,请删除第一个字符0b并填充缓冲区的结尾 然后,bitcontents是一个以11111111…开头的字符串。。。。。只需使用.txt扩展名重命名文件并用文本编辑器打开它,您将看到它是一个只包含ASCII字符0和1的大文件

由于头文件是ffd8,因此文件将以10 1开头。所以错误是以0x31 0x31开始,因为0x31是1的ascii码

您需要的是转换二进制字节数组中的六位字符串JPG内容

fileimage = ''.join([ jpgcontent[i:i+2] for i in range(0, len(jpgcontent), 2]
然后,您可以安全地将fileimage缓冲区复制到二进制文件:

file = open(sys.argv[1] + "_tr.jpg", "wb")
file.write(fileimage)

哎呀,你没有做你期望的事。bin生成一个字符串,其中包含二进制形式的值。如果输入文件中的内容是:

saver是一个文本形式的十六进制字符字符串,类似于初始字符串132ABC的313233414243 jpgcontents的格式相同,以ffd8开头,以ffd9结尾 然后应用神奇的公式binintjpgcontents,scale[2:] 将十六进制字符串转换为长整数 将长整数转换为二进制表示字符串-此部分将转换整数255中的hexa ff,并以字符串0b11111111结尾 如果需要,请删除第一个字符0b并填充缓冲区的结尾 然后,bitcontents是一个以11111111…开头的字符串。。。。。只需使用.txt扩展名重命名文件并用文本编辑器打开它,您将看到它是一个只包含ASCII字符0和1的大文件

由于头文件是ffd8,因此文件将以10 1开头。所以错误是以0x31 0x31开始,因为0x31是1的ascii码

您需要的是转换二进制字节数组中的六位字符串JPG内容

fileimage = ''.join([ jpgcontent[i:i+2] for i in range(0, len(jpgcontent), 2]
然后,您可以安全地将fileimage缓冲区复制到二进制文件:

file = open(sys.argv[1] + "_tr.jpg", "wb")
file.write(fileimage)

最简单的方法是使用binascii模块:


最简单的方法是使用binascii模块:


谢谢,我试试看。但我不确定为什么错误会给我文件以0x31开头。这个十六进制值来自哪里?如果在文本编辑器中打开jpg,您很可能会看到十六进制字符串的字符串表示形式。因为默认情况下,用write-only打开文件时会打印一个字符串。所以,如果我使用wb类型并将它们作为二进制类型,它会解决问题吗?或者你的意思是在文本编辑器中打开jpg本身就是个问题?使用wb应该可以。jpg的第一个字符是0x31,转换为ASCII的字符是1。仅使用wb是不够的。bitcontents不是正确二进制格式的所需数据,它是一个ASCII 0和1字符串。谢谢,我会尝试。但我不确定为什么错误会给我文件以0x31开头。这个十六进制值来自哪里?如果在文本编辑器中打开jpg,您很可能会看到十六进制字符串的字符串表示形式。因为默认情况下,用write-only打开文件时会打印一个字符串。所以,如果我使用wb类型并将它们作为二进制类型,它会解决问题吗?或者你的意思是在文本编辑器中打开jpg本身就是个问题?使用wb应该可以。jpg的第一个字符是0x31,转换为ASCII的字符是1。仅使用wb是不够的。bitcontents不是正确二进制格式的所需数据,它是一个ASCII 0和1字符串。哪一行导致异常/错误?实际上代码本身不会给出错误。但是,当我打开生成的jpg文件时,会收到错误消息,而不是JPEG文件:以0x31 0x31开头,因此我无法成功打开jpg文件,这一行导致异常/错误?实际上代码本身不会给出错误。但是,当我打开生成的jpg文件时,会收到错误消息,而不是JPEG文件:以0x31 0x31开头,因此我无法成功打开jpg文件