2025, Oct 31 22:01
दो .SET बाइनरी फाइलों को बाइट-दर-बाइट मिलाने का सुरक्षित तरीका (Python)
Python से दो .SET बाइनरी फाइलों का बाइट-दर-बाइट तुलना और सुरक्षित, विश्वसनीय पैचिंग: बदलाव मेमोरी में करें, अंत में एक बार लिखें, truncate से आकार सही रखें.
जब आपको दो बाइनरी .SET फाइलों की सामग्री को बाइट-दर-बाइट संरेखित करना हो, तो फर्क को वहीं पर पैच करने की इच्छा स्वाभाविक है। इस मामले में मकसद था—काम कर रहे GPS रिसीवर की SET फाइल से भिन्न बाइट्स को उस फाइल में कॉपी करना जो बूट लूप में फंसे रिसीवर से आई थी। Windows 11 पर शुरुआती Python तरीका बिना किसी त्रुटि के चला, लेकिन लक्ष्य फाइल में कोई बदलाव नहीं हुआ। समाधान आखिरकार इस बात पर आकर रुका कि डेटा कब और कैसे लिखा जा रहा है।
समस्या का सेटअप और असफल उदाहरण
इरादा था दो फाइलों की तुलना करना और इटरेशन के दौरान सीधे लक्ष्य फाइल में अंतर लिखना:
from itertools import zip_longest
counter = 0
with open(r"C:\Users\jimal\Desktop\APP2\mgnShell.set", "r+b") as bad_fp, open(r"E:\APP\mgnShell.set", "rb") as good_fp:
bad_blob = bad_fp.read()
bad_bytes = bytearray(bad_blob)
good_blob = good_fp.read()
good_bytes = bytearray(good_blob)
for b_bad, b_good in zip_longest(bad_bytes, good_bytes):
counter += 1
if b_bad != b_good:
bad_fp.seek(bad_bytes.index(b_bad))
if b_good == None:
bad_fp.write(bytes(0x00))
else:
bad_fp.write(bytes(b_good))
print(f"Done! Count was {counter}")असल में गड़बड़ी कहाँ थी
मुख्य मसला OS permissions या फोल्डर attributes का नहीं था। दिक्कत लिखने की रणनीति में थी। लूप के भीतर लिखना ऑपरेशन के प्रवाह के खिलाफ जाता है। पहले सभी बदलावों को इकट्ठा करना चाहिए, और उसके बाद ही लिखना चाहिए। मतलब, मेमोरी में मौजूद bytearray को अपडेट करें, और लूप पूरा होने के बाद उसी अंतिम बफर को डिस्क पर लिखें।
समाधान का दूसरा पहलू भी है: डेटा पर इटरेट करते हुए फाइल को सीधे बदलना ऑफ़सेट्स और अंतिम आकार पर नियंत्रण को उलझा देता है। पहले bytearray को अपडेट करना और फिर एक बार में लिखना सुनिश्चित करता है कि फाइल को सुसंगत और पूरा परिणाम मिले।
कारगर तरीका
सुधारा गया प्रवाह दोनों फाइलें पढ़ता है, अंतर निकालता है, मेमोरी में लक्ष्य बफर अपडेट करता है, और लूप के बाद ही अंतिम बफर को फाइल में लिखकर उसे truncate करता है:
counter = 0
with open(r"C:\Users\jimal\Desktop\APP2\mgnShell.set", "rb+") as dst_fp, open(r"E:\APP\mgnShell.set", "rb") as src_fp:
dst_raw = dst_fp.read()
dst_arr = bytearray(dst_raw)
src_raw = src_fp.read()
src_arr = bytearray(src_raw)
for b_dst, b_src, idx in zip(dst_arr, src_arr, range(len(dst_arr))):
counter += 1
if b_dst != b_src:
dst_arr[idx] = b_src
data_out = dst_arr[0:len(src_arr)]
dst_fp.seek(0)
dst_fp.write(data_out)
dst_fp.truncate()
print(f"Done! Count was {counter}")यह क्यों मायने रखता है
बाइनरी फाइलों में संपादन कठोर होते हैं। लिखने के समय या ऑफ़सेट प्रबंधन में छोटी-सी चूक भी ऐसे no-op या आंशिक writes तक ले जा सकती है जो चुपचाप इच्छित असर नहीं छोड़ते। सभी संशोधनों को पहले मेमोरी में समेटकर एक ही बार कमिट करने से साफ सीमा मिलती है: पहले अंतर निकाले जाते हैं; स्थायी लेखन बाद में होता है। यह सरल मानसिक मॉडल—read, transform, write—से भी मेल खाता है, जिसे परखना और समझना आसान है।
यदि लक्ष्य दो फाइलों को समान बनाना है, तो कई बार सबसे सरल रास्ता है—एक फाइल को दूसरी से बदल देना। जब रूपांतरण जरूरी हो, तो अक्सर ज्यादा आसान और सुरक्षित होता है फाइलों को केवल पढ़ने के लिए खोलना, परिणाम मेमोरी में तैयार करना, और फिर लिखने के लिए खोलकर अंतिम बफर को सहेजना। अगर कुछ गड़बड़ लगे, तो साधारण print debugging—टाइप, लंबाइयाँ और लूप में प्रगति छापना—हर चरण पर कोड वास्तव में क्या कर रहा है, यह पक्का करने में मदद करता है।
मुख्य बातें
दो फाइलों के बीच बाइट-स्तरीय समकालिकरण के लिए सभी बदलाव मेमोरी में निकालें और अंत में एक बार लिखें। शुरुआत पर seek करें, तैयार बफर लिखें और truncate करें, ताकि डिस्क पर मौजूद फाइल का आकार स्रोत के बराबर हो। यदि बस समान सामग्री चाहिए, तो सीधे प्रतिस्थापन पर विचार करें। और निदान करते समय अदृश्य को दृश्य बनाइए: डेटा और नियंत्रण प्रवाह को लेकर अपनी धारणाओं की जांच के लिए कोड में प्रिंट्स जोड़ें।
यह लेख StackOverflow के प्रश्न और jacob malu के उत्तर पर आधारित है; प्रश्न भी jacob malu द्वारा पूछा गया था।