我正在尝试读取一个以空字符结尾的字符串,但在解压缩字符串并将其与字符串放在一起时我遇到了问题。
这是代码:
def readString(f):
str = ''
while True:
char = readChar(f)
str = str.join(char)
if (hex(ord(char))) == '0x0':
break
return str
def readChar(f):
char = unpack('c',f.read(1))[0]
return char
现在这给了我这个错误:
TypeError: sequence item 0: expected str instance, int found
我也在尝试以下方法:
char = unpack('c',f.read(1)).decode("ascii")
但它让我失望: AttributeError:'tuple'对象没有属性'decode'
我甚至不知道如何读取字符并将其添加到字符串中,有没有正确的方法来执行此操作?
答案 0 :(得分:1)
(编辑版本2,最后添加额外的方式)
也许有一些图书馆可以帮助你解决这个问题,但是由于我不了解它们,我们可以用我们所知道的方式解决问题。
在python中2字节和字符串基本相同,在python 3中更改字符串是py2中的字符串是unicode而字节是它自己的单独类型,这意味着你不需要定义读取char如果你在py2中,因为不需要额外的工作,所以我认为你不需要unpack
这个特殊情况的函数,考虑到这一点,我们定义新的readString
def readString(myfile):
chars = []
while True:
c = myfile.read(1)
if c == chr(0):
return "".join(chars)
chars.append(c)
就像你的代码一样,我当时读了一个字符,但是我将它们保存在一个列表中,原因是字符串是不可变的,因此执行str + = char会导致不必要的副本;当我发现空字符返回连接字符串。而chr
是ord
的倒数,它会给出给定ascii值的字符。这将排除null字符,如果需要只移动附加...
现在让我们使用您的sample file
进行测试 例如,让我们尝试阅读" Sword_Wea_Dummy"从它with open("sword.blendscn","rb") as archi:
#lets simulate that some prior processing was made by
#moving the pointer of the file
archi.seek(6)
string=readString(archi)
print "string repr:", repr(string)
print "string:", string
print ""
#and the rest of the file is there waiting to be processed
print "rest of the file: ", repr(archi.read())
这是输出
string repr: 'Sword_Wea_Dummy'
string: Sword_Wea_Dummy
rest of the file: '\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6=\x00\x00\x00\x00\xeaQ8?\x9e\x8d\x874$-i\xb3\x00\x00\x00\x00\x9b\xc6\xaa2K\x15\xc6=;\xa66?\x00\x00\x00\x00\xb8\x88\xbf@\x0e\xf3\xb1@ITuB\x00\x00\x80?\xcd\xcc\xcc=\x00\x00\x00\x00\xcd\xccL>'
其他测试
>>> with open("sword.blendscn","rb") as archi:
print readString(archi)
print readString(archi)
print readString(archi)
sword
Sword_Wea_Dummy
ÍÌÌ=p=Š4:¦6¿JÆ=
>>> with open("sword.blendscn","rb") as archi:
print repr(readString(archi))
print repr(readString(archi))
print repr(readString(archi))
'sword'
'Sword_Wea_Dummy'
'\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6='
>>>
现在我考虑一下,你提到数据部分是固定大小的,如果对所有文件都是如此,那么所有文件的结构如下
[unknow size data][know size data]
然后这是我们可以利用的模式,我们只需要知道文件的大小,我们就可以顺利地获得这两个部分
import os
def getDataPair(filename,knowSize):
size = os.path.getsize(filename)
with open(filename, "rb") as archi:
unknown = archi.read(size-knowSize)
know = archi.read()
return unknown, know
并且通过了解数据部分的大小,它的使用很简单(我通过使用前面的例子来获得)
>>> strins_data, data = getDataPair("sword.blendscn", 80)
>>> string_data, data = getDataPair("sword.blendscn", 80)
>>> string_data
'sword\x00Sword_Wea_Dummy\x00'
>>> data
'\xcd\xcc\xcc=p=\x8a4:\xa66\xbfJ\x15\xc6=\x00\x00\x00\x00\xeaQ8?\x9e\x8d\x874$-i\xb3\x00\x00\x00\x00\x9b\xc6\xaa2K\x15\xc6=;\xa66?\x00\x00\x00\x00\xb8\x88\xbf@\x0e\xf3\xb1@ITuB\x00\x00\x80?\xcd\xcc\xcc=\x00\x00\x00\x00\xcd\xccL>'
>>> string_data.split(chr(0))
['sword', 'Sword_Wea_Dummy', '']
>>>
现在让每个字符串进行简单的拆分就足够了,你可以将data
中包含的其余文件传递给适当处理的函数
答案 1 :(得分:0)
这是一个(ab)使用__iter __'鲜为人知的" sentinel"参数:
{{1}}
答案 2 :(得分:0)
这是我写的一个模块,它读取任意终止的行(包括空终止): readline0
它应该比执行单一字符读取的版本快得多。
它也可以在Python 2.x和3.x上运行
我经常使用它。它似乎运作良好。
HTH。
答案 3 :(得分:0)
一次执行一个字符的文件I / O速度非常慢。
现在在pypi:https://pypi.org/project/readline0/上使用readline0。或类似的东西。
在3.x版本中,有一个“换行”参数可以打开,但它似乎不如readline0灵活。
答案 4 :(得分:0)
怎么样:
myString = myNullTerminatedString.split("\x00")[0]
例如:
myNullTerminatedString = "hello world\x00\x00\x00\x00\x00\x00"
myString = myNullTerminatedString.split("\x00")[0]
print(myString) # "hello world"
这是通过在空字符上拆分字符串来实现的。由于字符串应在第一个空字符处终止,因此我们只需在拆分后获取列表中的第一项。如果分隔符不存在,split
将返回一个项目的列表,因此即使根本没有空终止符,它仍然有效。
它也适用于字节字符串:
myByteString = b'hello world\x00'
myStr = myByteString.split(b'\x00')[0].decode('ascii') # "hello world" as normal string
如果您正在读取文件,则可以进行相对较大的读取 - 估计需要读取多少才能找到空字符串。这比逐字节读取要快得多。例如:
resultingStr = ''
while True:
buf = f.read(512)
resultingStr += buf
if len(buf)==0: break
if (b"\x00" in resultingStr):
extraBytes = resultingStr.index(b"\x00")
resultingStr = resultingStr.split(b"\x00")[0]
break
# now "resultingStr" contains the string
f.seek(0 - extraBytes,1) # seek backwards by the number of bytes, now the pointer will be on the null byte in the file
# or f.seek(1 - extraBytes,1) to skip the null byte in the file
答案 5 :(得分:-1)
这是我的实现方式
import struct
def read_null_str(f):
r_str = ""
while 1:
back_offset = f.tell()
try:
r_char = struct.unpack("c", f.read(1))[0].decode("utf8")
except:
f.seek(back_offset)
temp_char = struct.unpack("<H", f.read(2))[0]
r_char = chr(temp_char)
if ord(r_char) == 0:
return r_str
else:
r_str += r_char