Найти - Пользователи
Полная версия: Запись и чтение из бинарного файла.
Начало » Python для новичков » Запись и чтение из бинарного файла.
1 2
nauman
Происходит ошибка при чтении раннее записанной информации из файла.
Вот проблемный кусок кода:
#!/usr/bin/python
import cPickle, struct
l
D={'user': 'password'}
im_dump=cPickle.dumps(D, -1)
length_dump=len(im_dump)

#Пишем в файл
data=str(struct.pack('>i4sh',length_dump,im_dump,8))
pass_file=open('c:\\Python26\\passwd.txt','wb')
pass_file.write(data)
pass_file.close()
print data

#Читаем из файла
pass_file=open('c:\\Python26\\passwd.txt','rb')
test_dump=pass_file.read()
print test_dump
data=str(struct.unpack('>i4sh',test_dump))
D=dict(cPickle.loads(data))
pass_file.close()
print data
Это результат:

Ђ}qUuserqUpasswordqs.

Traceback (most recent call last):
File "C:\Python26\mystruct.py", line 21, in <module>
D=dict(cPickle.loads(data))
UnpicklingError: unpickling stack underflow
Я так понял проблема с обратным преобразованием struct, cPickle уже не может распознать?
Что я тут делаю не так, похожий пример взят из книги.
Windows XP, Python 2.6.4
Ed
Проблема с тем, что вы пакуете 4 байта из 27 нужных. Естественно, что потом не распикливается.
In [2]: len(cPickle.dumps({'user': 'password'}, -1))
Out[2]: 27
PS: И еще вы все, то, что распаковали, пытаетесь скормить pickle, а там еще 2 числа, которые там совсем не нужны. Собственно поэтому оно и ругается, встречает вашу семерку.
nauman
Ed, я заменил “7” на “length_dump=len(im_dump)”, мой первый пост.
Сообщение об ошибке тоже изменилось, я его вставил вместо первого.

Ed
а там еще 2 числа, которые там совсем не нужны.
Я что то не понимаю, какие два числа, как это исправить?
Ed
Ну давайте разбираться. Я буду задавать вопросы, а вы будете отвечать.
1. Что означает цифра 4 в ‘>i4sh’?
2. Что означает цифра 8 в struct.pack('>i4sh',length_dump,im_dump,8)
3. Зачем вы преобразовываете результат stuct.pack в строку?
4. Как вы собираетесь делать обратное преобразование, прочитав эту строку из файла?

Для начала достаточно. Жду ответов.
nauman
1. Понятия не имею, поэтому и спрашиваю. Документация на английском, в нем я не настолько силен, чтобы детально понять, к сожалению. В основном ориентировался русскоязычным учебником, там вкратце затрагивался struct, идея понравилась решил реализовать.
2. Аналогично.
3. Это я исправил. Но при распаковке пикл принимает только строку.
4. Словарь -> cPickle объект -> strukt -> загоняем в бинарный файл. Обратно: открываем файл -> распаковываем struct-ом -> передаем cPickle-у -> записываем в словарь. По идее пикл должен бы получить стрку в томже виде, в каком ее туда положил.

Задумка была такая, хотелось бы получить помощь в этом вопросе.
Ed
nauman
1. Понятия не имею
Упс. То есть вы написали эту стороку: data=str(struct.pack('>i4sh',length_dump,im_dump,8))
не имея понятия что такое ‘>i4sh’ и 8? Просто скопировали откуда-то, что ли?

Задумка была такая, хотелось бы получить помощь в этом вопросе.
Я и пытаюсь эту помощь оказать. Думал, что вы знаете что вы написали.

Ладно, пойдем другим путем.
Что вы хотите сделать вообще? Если просто сохранить словарик D в файл, а потом прочитать обратно, то struct вам не нужен, попробуйте просто писать то, что выдал Cpickle.dumps в файл и соответственно потом читать без всяких struct.

Если хотите сделать что-то другое, то рассказывайте тогда что именно.
nauman
Если объясните, что такое >i4sh и 8, буду рад, так как думаю, что может проблема в них.
Мне важен принцип правильной работы в связке объект -> cPickle -> struct и обратно, так как он довольно часто будет употребляться. Без struct все нормально работает, т.е. когда cPickle пишет в файл.
Что касается приведенного кода. Основная, может параноидальная идея - имя и зашифрованный пароль скрыть в бинарном файле, подальше от глаз. Пикл в созданном файле отображает имя и пароль, даже если запускается с параметром -1. Я мог бы обойтись и без Пикла, но с ним гораздо удобнее.
Ed
>i4sh - это формат, подразумевает упаковывание в структуру 3х объектов - целое(i), строку из 4 символов(4s) и короткое целое(h). То есть вы запаковываете в структуру целое - сначала было 7, а потом вы поменяли это на длину запикленого, строку длиной 4 (начало вашей запикленой строки) и короткое целое 8. Я поэтому и интересовался что это за волшебные цифры 7 и 8, которые вы пакуете вместе с тем, что вам нужно.

Идея в целом не параиноидальная, но не очень хорошая.
Вот смотрите что мы имеем:
это то, что выдает pickle:
In [6]: cPickle.dumps({'user': 'password'})
Out[6]: "(dp1\nS'user'\np2\nS'password'\np3\ns."
Тут вы правы, все видно.
Но вот, что у нас выдает struct.pack:
In [7]: pickled = cPickle.dumps({'user': 'password'})
In [8]: struct.pack('%ds' % len(pickled), pickled)
Out[8]: "(dp1\nS'user'\np2\nS'password'\np3\ns."
Как видите тоже не фонтан. Фактически это тоже самое. Даже если вы добавите какой-нибудь мусор строку все равно будет видно.
Так что если хотите зашифровать - то шифруйте. Упаковка строк в структуру - это не шифрование.
nauman
Этого было бы достаточно:
import hashlib
D={'user': (hashlib.md5('password').hexdigest())}
просто для большей надежности хотел скрыть всякое отображение, даже имени.
При не правильном, в моем варианте упаковывании в структуру ‘>i4sh’, в файле отображался мусор.
Ed, спасибо за информацию.
knkd
Если посто хочется скрыть от шаловливых ручек пользователей (а не взлома), то гораздо проще вот так:

#!/usr/bin/env python

## o* - open
## e* - encode
## d* - decode
odata = "username:knkd\x00passwd:superpassword"
edata = odata.encode('bz2').encode('hex')
print edata
-> '425a6839314159265359f1d03e7c00000fc98040000010260bda80200021a9a68c4da6a100001f8d3e128de762cc5517490dc8a3a4c3e2ee48a70a121e3a07cf80'
ddata = edata.decode('hex').decode('bz2')
repr(ddata)
-> "'username:knkd\\x00passwd:superpassword'"
Ну или что-то подобное.
В вашем случае это намного надёжнее в плане последующего восстановления :)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB