टेक्स्ट फ़ाइल को कैसे संशोधित करें?


175

मैं पायथन का उपयोग कर रहा हूं, और फ़ाइल को हटाने या कॉपी किए बिना एक टेक्स्ट फ़ाइल में एक स्ट्रिंग सम्मिलित करना चाहूंगा। मैं उसे कैसे कर सकता हूँ?


1
आप एलेक्स मार्टेली के इस जवाब का उल्लेख कर सकते हैं ।
आलोक



@ अन्य पोस्ट वैसे भी किसी पाठ फ़ाइल की निर्दिष्ट स्थिति में लाइन डालने का एक डुप्लिकेट है और निश्चित रूप से यहाँ स्पष्ट रूप से उत्तर दिए गए हैं, अन्य तरीके के बजाय यहाँ अपना उत्तर क्यों न जोड़ें? स्वीकृत उत्तर किसी अच्छे प्रश्न की आवश्यकता नहीं है।
भार्गव राव

@BhargavRao वोट से पीछे हट गए। मुझे लगता है कि नकल हालांकि पाया जाना चाहिए!
एनी मेनन

जवाबों:


134

दुर्भाग्य से इसे दोबारा लिखे बिना किसी फाइल के बीच में डालने का कोई तरीका नहीं है। जैसा कि पिछले पोस्टरों ने संकेत दिया है, आप एक फ़ाइल या इसके एक हिस्से को अधिलेखित कर सकते हैं, लेकिन यदि आप शुरुआत या मध्य में सामान जोड़ना चाहते हैं, तो आपको इसे फिर से लिखना होगा।

यह एक ऑपरेटिंग सिस्टम चीज़ है, पायथन चीज़ नहीं। यह सभी भाषाओं में समान है।

मैं आमतौर पर फ़ाइल से पढ़ता हूं, संशोधन करता हूं और इसे एक नई फ़ाइल पर लिखता हूं जिसे myfile.txt.tmp या उसके बाद कुछ कहा जाता है। यह पूरी फ़ाइल को मेमोरी में पढ़ने से बेहतर है क्योंकि फ़ाइल उसके लिए बहुत बड़ी हो सकती है। एक बार अस्थायी फ़ाइल पूरी हो जाने के बाद, मैं इसे मूल फ़ाइल के समान नाम देता हूँ।

यह करने का एक अच्छा, सुरक्षित तरीका है क्योंकि यदि फ़ाइल किसी कारण से क्रैश या एबॉर्ट्स लिखती है, तो आपके पास अभी भी आपकी अछूता मूल फ़ाइल है।


3
क्या awk / sed जैसे यूनिक्स उपकरण अपने कोड में कुछ ऐसा ही करते हैं?
मनीष गिल

यह सच नहीं है कि यह सभी भाषाओं में समान है। ActionScript में: fileStream.openAsync (फ़ाइल नाम, FileMode.UPDATE); फिर मैं जिस फाइल को चाहता हूं उसमें कहीं भी जा सकता हूं और कुछ भी बदल सकता हूं।
एंड्रयूबेंजिन

2
@AndrewBenjamin क्या आपको पता है कि ActionScript क्या सिस्टम कॉल कर रहा है? क्या कोई संभावना है कि ओपनएस्क्यू फाइल को पढ़ता है और कॉल के बाद एक नया लिखता है?
एलेक्सलॉर्ड टॉर्सन

@Rawrgulmuffins मैं नहीं। हालाँकि, मुझे पता है कि यह पूरी फ़ाइल को मेमोरी में नहीं पढ़ रहा है, क्योंकि मैंने इसका उपयोग कई जीबी की फाइल को संभालने के लिए किया है। मुझे संदेह है कि यह सी # स्ट्रीमराइटर के साथ लिखने के समान है। मैं अजगर को बड़े पैमाने पर विकास और फ़ाइल हेरफेर के बजाय छोटी चीजों को जल्दी से करने के लिए एक उपकरण के रूप में देखता हूं।
एंड्रयूबेंजिन

4
@AndrewBenjamin, उपयोगकर्ता फ़ाइल में इधर-उधर तलाश करने और उसे बदलने के बारे में नहीं पूछ रहा है (हर भाषा जो मुझे पता है कि ऐसा कर सकते हैं); वह पाठ सम्मिलित करने के बारे में पूछ रहा है, जो कि फ़ाइल में पहले से ही परिवर्तन / ओवरराइटिंग से अलग है। हो सकता है कि व्यावहारिक अनुप्रयोग में यह अलग है, लेकिन एक्शनस्क्रिप्ट एपीआई में मुझे जो कुछ भी नहीं मिला है वह बताता है कि यह इस संबंध में किसी भी अन्य भाषा से अलग व्यवहार करता है।
Eestrada

104

निर्भर करता है कि आपकी क्या करने की इच्छा है। संलग्न करने के लिए आप इसे "ए" के साथ खोल सकते हैं:

 with open("foo.txt", "a") as f:
     f.write("new line\n")

यदि आप पहले फ़ाइल से कुछ पढ़ना चाहते हैं, तो:

with open("foo.txt", "r+") as f:
     old = f.read() # read everything in the file
     f.seek(0) # rewind
     f.write("new line\n" + old) # write the new line before

9
बस एक छोटा सा जोड़, withपायथन 2.5 में बयान का उपयोग करने के लिए आपको " भविष्य के आयात के साथ_स्टैटमेंट" से जोड़ना होगा । इसके अलावा, withबयान के साथ फाइलें खोलना निश्चित रूप से अधिक पठनीय है और मैन्युअल समापन की तुलना में कम त्रुटि वाला है।
अलेक्जेंडर कोजेवनिकोव

2
आप fileinputसहायक को गंदे खुले / पढ़ने / संशोधित / लिखने / नियमित रूप से inline=Trueआरजी का उपयोग करते समय प्रतिस्थापित करने के साथ काम करने पर विचार कर सकते हैं । यहाँ उदाहरण: stackoverflow.com/a/2363893/47390
mikegreenberg

3
बस फ़ाइल को बंद करने के लिए मत भूलना। f.Close()
डी। रोराडो

5
यह एक ऐसी शैली नहीं है जिसका मैं उपयोग करता हूं, डी। रोराडो, लेकिन जब शैली का उपयोग करते हैं, तो मुझे नहीं लगता कि आपको मैन्युअल रूप से बंद करने की आवश्यकता है। इसके साथ बनाए गए संसाधन का ट्रैक रखता है।
क्रिस

4
आपको फ़ाइल को मैन्युअल रूप से बंद करने की आवश्यकता नहीं है। यहां "के साथ" का उपयोग करने का पूरा बिंदु है। (खैर, वास्तव में, पायथन ऐसा करता है जैसे ही फ़ाइल ऑब्जेक्ट कचरा एकत्र किया जाता है, जो कि सीपीथॉन में होता है जब यह बाध्य नाम गुंजाइश से बाहर हो जाता है ... लेकिन अन्य कार्यान्वयन नहीं करते हैं, और सीपीथॉन इसे किसी दिन करना बंद कर सकता है , इसलिए "के साथ" की सिफारिश की गई है)
जुरगेन ए इरहड़

71

fileinputयदि आप inplace = 1 पैरामीटर का उपयोग करते हैं, तो पायथन मानक लाइब्रेरी का मॉड्यूल एक फ़ाइल इनाइल को फिर से लिखेगा।

import sys
import fileinput

# replace all occurrences of 'sit' with 'SIT' and insert a line after the 5th
for i, line in enumerate(fileinput.input('lorem_ipsum.txt', inplace=1)):
    sys.stdout.write(line.replace('sit', 'SIT'))  # replace 'sit' and write
    if i == 4: sys.stdout.write('\n')  # write a blank line after the 5th line

1
यह कैसे python3 में काम करने की उम्मीद है? मैंने अभी एक ऐप को पोर्ट किया है, जिसमें अजगर से लेकर अजगर 3 तक का कुछ कोड है और मुझे अभी इस पर काम करने का मौका नहीं मिला है। 'लाइन' वेरिएबल एक बाइट्स प्रकार है, मैंने इसे यूनिकोड में डिकोड करने और फिर इसे संशोधित करने और फिर इसे बाइट्स में वापस एन्कोड करने की कोशिश की, लेकिन यह सिर्फ सही काम नहीं करेगा। इसने कुछ अपवाद उठाए जिन्हें मैं अपने सिर के ऊपर से याद नहीं कर सकता। किसी भी सफलता के साथ लोग python3 में फाइलइनपुट inplace = 1 का उपयोग कर रहे हैं?
5

1
@Robru: यहां पायथन 3 कोड
jfs

13
लेकिन इसकी कोई समस्या नहीं है कि आपने इसे पहले एक महत्वहीन फ़ाइल पर परीक्षण किया है?
पाउला लिविंगस्टोन

33

एक जगह पर एक फ़ाइल को फिर से लिखना अक्सर पुरानी कॉपी को संशोधित नाम के साथ सहेज कर किया जाता है। यूनिक्स लोग ~पुराने को चिह्नित करने के लिए एक जोड़ते हैं । विंडोज के लोग सभी प्रकार की चीजें करते हैं - .bak या .old जोड़ें - या पूरी तरह से फ़ाइल का नाम बदलें या नाम के सामने ~ डाल दें।

import shutil
shutil.move( afile, afile+"~" )

destination= open( aFile, "w" )
source= open( aFile+"~", "r" )
for line in source:
    destination.write( line )
    if <some condition>:
        destination.write( >some additional line> + "\n" )
source.close()
destination.close()

इसके बजाय shutil, आप निम्न का उपयोग कर सकते हैं।

import os
os.rename( aFile, aFile+"~" )

1
अछा लगता है। आश्चर्य है कि क्या .readlines () स्रोत को पुनरावृत्त करने से बेहतर है?
बोजडोज़

2
@bozdoz: पुनरावृत्ति बेहतर है क्योंकि रीडलाइन पूरी फ़ाइल पढ़ती है। बड़ी फ़ाइलों के लिए अच्छा नहीं है। बेशक, यह माना जाता है कि आप अपने संशोधनों को इस तरह से स्थानीय तरीके से कर सकते हैं। कभी-कभी आप नहीं कर सकते, या आपका कोड बहुत अधिक जटिल हो जाता है।
जर्गेन ए। इरहार्ड

@ S.Lott: os.rename(aFile, aFile + "~")स्रोत फ़ाइल का नाम संशोधित करेगा, प्रतिलिपि नहीं बना रहा है।
पैतापोम

14

पायथन का mmap मॉड्यूल आपको एक फ़ाइल में सम्मिलित करने की अनुमति देगा। निम्न नमूना दिखाता है कि यह यूनिक्स में कैसे किया जा सकता है (विंडोज मिमीप अलग हो सकता है)। ध्यान दें कि यह सभी त्रुटि स्थितियों को संभालता नहीं है और आप मूल फ़ाइल को दूषित या खो सकते हैं। इसके अलावा, यह यूनिकोड स्ट्रिंग्स को हैंडल नहीं करेगा।

import os
from mmap import mmap

def insert(filename, str, pos):
    if len(str) < 1:
        # nothing to insert
        return

    f = open(filename, 'r+')
    m = mmap(f.fileno(), os.path.getsize(filename))
    origSize = m.size()

    # or this could be an error
    if pos > origSize:
        pos = origSize
    elif pos < 0:
        pos = 0

    m.resize(origSize + len(str))
    m[pos+len(str):] = m[pos:origSize]
    m[pos:pos+len(str)] = str
    m.close()
    f.close()

यह बिना संभव नहीं है कि बिना mmap के भी 'r +' मोड में खोली गई फ़ाइलों के साथ, लेकिन यह कम सुविधाजनक और कम कुशल है क्योंकि आपको फ़ाइल की सामग्री को प्रविष्टि स्थिति से EOF में अस्थायी रूप से पढ़ना और स्टोर करना होगा - जो हो सकता है विशाल होना।


14

जैसा कि एडम ने उल्लेख किया है कि आपको दृष्टिकोण पर निर्णय लेने से पहले अपनी प्रणाली की सीमाओं को ध्यान में रखना होगा कि क्या आपके पास यह सब पढ़ने के लिए पर्याप्त मेमोरी है या नहीं और इसे फिर से लिखना है।

यदि आप एक छोटी फ़ाइल के साथ काम कर रहे हैं या कोई स्मृति समस्या नहीं है तो यह मदद कर सकता है:

विकल्प 1) पूरी फ़ाइल को मेमोरी में पढ़ें, लाइन के पूरे या भाग पर एक रेगेक्स प्रतिस्थापन करें और इसे उस लाइन के साथ बदलें और अतिरिक्त लाइन। आपको यह सुनिश्चित करने की आवश्यकता होगी कि फ़ाइल में 'मध्य रेखा' अद्वितीय है या यदि आपके पास प्रत्येक पंक्ति पर टाइमस्टैम्प है तो यह बहुत विश्वसनीय होना चाहिए।

# open file with r+b (allow write and binary mode)
f = open("file.log", 'r+b')   
# read entire content of file into memory
f_content = f.read()
# basically match middle line and replace it with itself and the extra line
f_content = re.sub(r'(middle line)', r'\1\nnew line', f_content)
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content 
f.truncate()
# re-write the content with the updated content
f.write(f_content)
# close file
f.close()

विकल्प 2) मध्य रेखा का पता लगाएं, और इसे उस रेखा के साथ बदलें और अतिरिक्त रेखा।

# open file with r+b (allow write and binary mode)
f = open("file.log" , 'r+b')   
# get array of lines
f_content = f.readlines()
# get middle line
middle_line = len(f_content)/2
# overwrite middle line
f_content[middle_line] += "\nnew line"
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content 
f.truncate()
# re-write the content with the updated content
f.write(''.join(f_content))
# close file
f.close()

2

इसे सफाई से करने के लिए एक छोटा वर्ग लिखा।

import tempfile

class FileModifierError(Exception):
    pass

class FileModifier(object):

    def __init__(self, fname):
        self.__write_dict = {}
        self.__filename = fname
        self.__tempfile = tempfile.TemporaryFile()
        with open(fname, 'rb') as fp:
            for line in fp:
                self.__tempfile.write(line)
        self.__tempfile.seek(0)

    def write(self, s, line_number = 'END'):
        if line_number != 'END' and not isinstance(line_number, (int, float)):
            raise FileModifierError("Line number %s is not a valid number" % line_number)
        try:
            self.__write_dict[line_number].append(s)
        except KeyError:
            self.__write_dict[line_number] = [s]

    def writeline(self, s, line_number = 'END'):
        self.write('%s\n' % s, line_number)

    def writelines(self, s, line_number = 'END'):
        for ln in s:
            self.writeline(s, line_number)

    def __popline(self, index, fp):
        try:
            ilines = self.__write_dict.pop(index)
            for line in ilines:
                fp.write(line)
        except KeyError:
            pass

    def close(self):
        self.__exit__(None, None, None)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        with open(self.__filename,'w') as fp:
            for index, line in enumerate(self.__tempfile.readlines()):
                self.__popline(index, fp)
                fp.write(line)
            for index in sorted(self.__write_dict):
                for line in self.__write_dict[index]:
                    fp.write(line)
        self.__tempfile.close()

तो आप इसे इस तरह से उपयोग कर सकते हैं:

with FileModifier(filename) as fp:
    fp.writeline("String 1", 0)
    fp.writeline("String 2", 20)
    fp.writeline("String 3")  # To write at the end of the file

यह मेरे लिए व्यक्तिगत रूप से काम नहीं करता है, यह फ़ाइल में पाठ जोड़ता है लेकिन यह सब कुछ पहले हटा देता है!
ब्रेट हॉकर

वास्तव में, यह बिल्कुल काम नहीं करता है। शर्म आनी चाहिए, क्योंकि यह एक अच्छा विचार था।
मारियो क्रुएलज

0

यदि आप कुछ यूनिक्स जानते हैं, तो आप निम्नलिखित प्रयास कर सकते हैं:

नोट: $ का अर्थ है कमांड प्रॉम्प्ट

कहो कि आपके पास ऐसी सामग्री के साथ एक फ़ाइल my_data.txt है:

$ cat my_data.txt
This is a data file
with all of my data in it.

फिर osमॉड्यूल का उपयोग करके आप सामान्य sedकमांड का उपयोग कर सकते हैं

import os

# Identifiers used are:
my_data_file = "my_data.txt"
command = "sed -i 's/all/none/' my_data.txt"

# Execute the command
os.system(command)

अगर आपको सेड के बारे में जानकारी नहीं है, तो इसे देखें, यह बेहद उपयोगी है।


3
यह पाइथोनिक नहीं है
डार्कसुनीउम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.