I am trying to write a program that will encrypt a file by using the .read()
function on the file content, which returns 98\xf1\xc6}xb1\*
.... I am trying to encrypt the file by looping through each character an incrementing its decimal number by 1 (numbers range from 0 -> 255). and then adding each incremented number to a new list.
new list looks something like this:
['«', 'û', '$', '\x00', 'Ú']
...
How do i convert this new list into a format which can be written in binary mode?
class Encrypting():
def __init__(self):
self.file = "files/test_img.jpg"
def open_file(self):
f = open(self.file, "rb")
self.content = f.read()
print(self.content)
f.close()
def convert_file_data(self):
self.new_values = []
for i in self.content:
new_val = i 1
if i == 255:
new_val = 0
new_val = chr(new_val)
self.new_values.append(new_val)
def rewrite(self):
f = open("files/conv1.jpg", "wb")
f.write(self.new_values)
f.close()
def main():
encrypt = Encrypting()
encrypt.open_file()
encrypt.convert_file_data()
encrypt.rewrite()
if __name__ == "__main__":
main()
CodePudding user response:
You could change:
f.write(self.new_values)
to:
f.write(''.join(self.new_values).encode('latin-1'))
combining the list
of str
into a single str
, then encoding it to latin-1
(which is the 1-1 mapping of the first 256 Unicode ordinals to bytes of the same values).
But the real solution is to change:
def convert_file_data(self):
self.new_values = []
for i in self.content:
new_val = i 1
if i == 255:
new_val = 0
new_val = chr(new_val)
self.new_values.append(new_val)
to:
def convert_file_data(self):
self.new_values = bytearray() # A mutable sequence of bytes, ints in range(256), so no type conversions needed
for i in self.content:
new_val = i 1
if i == 255:
new_val = 0
# chr conversion is unnecessary and counter-productive, so we just append the new byte
self.new_values.append(new_val)
This part:
new_val = i 1
if i == 255:
new_val = 0
could be simplified to:
new_val = (i 1) % 256
as well, which could then simplify the whole function to:
def convert_file_data(self):
self.new_values = bytearray() # A mutable sequence of bytes, ints in range(256), so no type conversions needed
for i in self.content:
self.new_values.append((i 1) % 256)
or even shorter, a simple genexpr fed to the bytes
/bytearray
constructor:
def convert_file_data(self):
self.new_values = bytes((i 1) % 256 for i in self.content)
Any of the bytes
or bytearray
based solutions are superior to storing a list
of str
in that:
- They require far less memory (the length one
str
s are likely cached, but the pointers to them stored in thelist
require 4-8 bytes a piece, vs. just one byte a piece for the rawbytes
) - It's less CPU intensive (appending individual bytes is cheaper, and there's no additional costs at the end to re
join
andencode
the data, it's already in the correct form natively)