अजगर पाठ फ़ाइलों को समाप्‍त करता है


168

मेरे पास 20 फ़ाइल नामों की सूची है, जैसे ['file1.txt', 'file2.txt', ...] । मैं इन फ़ाइलों को एक नई फ़ाइल में बदलने के लिए एक पायथन स्क्रिप्ट लिखना चाहता हूं। मैं प्रत्येक फ़ाइल को खोल सकता था f = open(...), कॉल करके लाइन द्वारा लाइन पढ़ सकता था f.readline(), और प्रत्येक लाइन को उस नई फ़ाइल में लिख सकता था। यह मेरे लिए बहुत "सुरुचिपूर्ण" नहीं लगता, विशेषकर वह हिस्सा जहाँ मुझे लाइन से // लिखना पड़ता है।

क्या पायथन में ऐसा करने का एक और "सुरुचिपूर्ण" तरीका है?


7
इसका अजगर नहीं है, लेकिन शेल स्क्रिप्टिंग में आप कुछ ऐसा कर सकते हैं cat file1.txt file2.txt file3.txt ... > output.txt। अजगर में, अगर आपको पसंद नहीं है readline(), तो हमेशा readlines()या बस read()
19 अगस्‍त 19

1
@jedwards केवल मॉड्यूल cat file1.txt file2.txt file3.txtका उपयोग करके कमांड चलाता है subprocessऔर आपका काम हो गया है। लेकिन मुझे यकीन नहीं है कि अगर catखिड़कियों में काम करता है।
अश्विनी चौधरी

5
एक नोट के रूप में, आप जिस तरह से वर्णन करते हैं वह फ़ाइल पढ़ने का एक भयानक तरीका है। withअपनी फ़ाइलों को ठीक से बंद करने के लिए कथन का उपयोग करें , और उपयोग करने के बजाय लाइनों को प्राप्त करने के लिए फ़ाइल पर पुनरावृति करें f.readline()
गारेथ लैटी

@jedwards बिल्ली तब काम नहीं करती जब टेक्स्ट फ़ाइल यूनिकोड हो।
एवी कोहेन

वास्तविक विश्लेषण waymoot.org/home/python_string
nu everest

जवाबों:


260

यह करना चाहिए

बड़ी फ़ाइलों के लिए:

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for fname in filenames:
        with open(fname) as infile:
            for line in infile:
                outfile.write(line)

छोटी फ़ाइलों के लिए:

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for fname in filenames:
        with open(fname) as infile:
            outfile.write(infile.read())

... और एक और दिलचस्प जो मैंने सोचा था :

filenames = ['file1.txt', 'file2.txt', ...]
with open('path/to/output/file', 'w') as outfile:
    for line in itertools.chain.from_iterable(itertools.imap(open, filnames)):
        outfile.write(line)

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


9
यह, बड़ी फ़ाइलों के लिए, बहुत अक्षम स्मृति होगी।
गारेथ लेटी

1
@ inspectorG4dget: मैं आपसे नहीं पूछ रहा था, मैं चश्मदीद से पूछ रहा था, जिन्होंने शिकायत की थी कि आपका समाधान कुशल नहीं था। मैं शर्त लगाने के लिए तैयार हूं कि यह ओपी के उपयोग के मामले के लिए पर्याप्त से अधिक कुशल है, और जो भी उपयोग मामले के लिए ध्यान में रखते हैं। अगर उसे लगता है कि यह नहीं है, तो यह उसकी ज़िम्मेदारी है कि वह यह साबित करने से पहले कि आप इसे ऑप्टिमाइज़ करते हैं।
अबार्नेट

2
क्या हम एक बड़ी फ़ाइल होने पर विचार कर रहे हैं ?
डी

4
@ डिडी: एक फ़ाइल इतनी बड़ी है कि यह सामग्री मुख्य मेमोरी में फिट नहीं होती है
इंस्पेक्टरगैजेट

7
बस दोहराना: यह गलत उत्तर है, shutil.copyfileobj सही उत्तर है।
पॉल क्रॉले

193

का उपयोग करें shutil.copyfileobj

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

import shutil

with open('output_file.txt','wb') as wfd:
    for f in ['seg1.txt','seg2.txt','seg3.txt']:
        with open(f,'rb') as fd:
            shutil.copyfileobj(fd, wfd)

2
for i in glob.glob(r'c:/Users/Desktop/folder/putty/*.txt'):अच्छी तरह से मैं बयान के लिए निर्देशिका में सभी फ़ाइलों को शामिल करने के लिए बदल दिया है, लेकिन मेरी output_fileबहुत तेजी से 100 gb की तरह बहुत तेजी से समय में वास्तव में बढ़ रही शुरू कर दिया।
R__raki__ 8

10
ध्यान दें, यदि EOL वर्ण नहीं हैं, तो अगली फ़ाइल के पहले तार के साथ प्रत्येक फ़ाइल के अंतिम तार को मर्ज किया जाएगा। मेरे मामले में मुझे इस कोड का उपयोग करने के बाद पूरी तरह से दूषित परिणाम मिला। मैंने सामान्य परिणाम प्राप्त करने के लिए copyfileobj के बाद wfd.write (b "\ n") को जोड़ा
Thelambofgoat

1
@Thelambofgoat मैं कहूंगा कि उस मामले में एक शुद्ध सहमति नहीं है, लेकिन हे, जो भी आपकी आवश्यकताओं के अनुरूप है।
HelloGoodbye

59

यह वास्तव में क्या fileinput के लिए है:

import fileinput
with open(outfilename, 'w') as fout, fileinput.input(filenames) as fin:
    for line in fin:
        fout.write(line)

इस उपयोग के मामले के लिए, यह वास्तव में फ़ाइलों पर मैन्युअल रूप से पुनरावृत्ति करने की तुलना में बहुत सरल नहीं है, लेकिन अन्य मामलों में, एक एकल पुनरावृत्ति करने वाला जो सभी फ़ाइलों पर पुनरावृति करता है जैसे कि वे एक ही फ़ाइल बहुत काम की हो। (इसके अलावा, यह तथ्य यह है कि fileinputप्रत्येक फ़ाइल को बंद कर दिया जाता है जैसे ही यह किया जाता है कि इसकी कोई आवश्यकता नहीं है withया नहींclose हर एक है, लेकिन यह सिर्फ एक पंक्ति बचत है, नहीं है कि एक समझौते के बड़ा।)

इसमें कुछ अन्य विशेषताएं हैं fileinput, जैसे प्रत्येक पंक्ति को फ़िल्टर करके फ़ाइलों के इन-प्लेस संशोधनों को करने की क्षमता।


जैसा कि टिप्पणियों में उल्लेख किया गया है, और एक और पोस्ट में चर्चा की गई है , fileinputपायथन 2.7 के लिए संकेत के रूप में काम नहीं करेगा। यहां कोड पायथन 2.7 को आज्ञाकारी बनाने के लिए मामूली संशोधन किया गया है

with open('outfilename', 'w') as fout:
    fin = fileinput.input(filenames)
    for line in fin:
        fout.write(line)
    fin.close()

@ लिट्टीवेयर: मुझे लगता है कि ज्यादातर लोग जिनके बारे में सीखते हैं, fileinputउन्हें बताया जाता है कि यह एक सरल sys.argv(या क्या optparseआदि के बाद args के रूप में छोड़ दिया जाता है ) को तुच्छ लिपियों के लिए एक बड़ी आभासी फ़ाइल में बदल दिया जाता है , और इसे किसी भी चीज़ के लिए उपयोग करने के लिए मत सोचो। और (यानी, जब सूची कमांड-लाइन आर्ग्स नहीं है)। या वे सीखते हैं, लेकिन फिर भूल जाते हैं- मैं इसे हर साल या दो बार फिर से
खोजता रहता हूं

1
@abament मुझे लगता for line in fileinput.input()है कि इस विशेष मामले में चुनने का सबसे अच्छा तरीका नहीं है: ओपी फाइलों को संक्षिप्त करना चाहता है, उन्हें लाइन से नहीं पढ़ना चाहिए जो निष्पादित करने के लिए एक सैद्धांतिक रूप से लंबी प्रक्रिया है
20

1
@eyquem: यह निष्पादित करने के लिए एक लंबी प्रक्रिया नहीं है। जैसा कि आपने स्वयं बताया, लाइन-आधारित समाधान एक समय में एक वर्ण नहीं पढ़ते हैं; वे विखंडू में पढ़ते हैं और एक बफर से लाइनों को खींचते हैं। I / O समय पूरी तरह से लाइन-पार्सिंग समय को स्वाहा कर देगा, इसलिए जब तक कि कार्यान्वयनकर्ता ने बफरिंग में कुछ भी मूर्खतापूर्ण नहीं किया, यह सिर्फ एक अच्छे बफर पर अनुमान लगाने की कोशिश की तुलना में तेज़ (और संभवतः इससे भी तेज़ होगा) अपने आप को आकार दें, यदि आपको लगता है कि 10000 एक अच्छा विकल्प है)।
२ert

1
@abarnert NO, 10000 अच्छा विकल्प नहीं है। यह वास्तव में एक बहुत बुरा विकल्प है क्योंकि यह 2 की शक्ति नहीं है और यह हास्यास्पद रूप से थोड़ा आकार है। बेहतर आकार 2097152 (2 21), 16777216 (2 24) या यहां तक ​​कि 134217728 (2 ** 27) होगा, क्यों नहीं?, 128 एमबी 4 जीबी की रैम में कुछ भी नहीं है।
12 को आइकॉमी

2
उदाहरण कोड पायथन 2.7.10 के लिए काफी वैध नहीं है और बाद में: stackoverflow.com/questions/30835090/…
CnrL

8

मैं लालित्य के बारे में नहीं जानता, लेकिन यह काम करता है:

    import glob
    import os
    for f in glob.glob("file*.txt"):
         os.system("cat "+f+" >> OutFile.txt")

8
तुम भी पाश से बच सकते हैं: ओएस आयात; os.system ("कैट फ़ाइल * .txt >> OutFile.txt")
lib

6
नहीं crossplatform और उन में रिक्त स्थान के साथ फ़ाइल नाम के लिए टूट जाएगा
भेड़

3
यह असुरक्षित है; इसके अलावा, catफ़ाइलों की सूची ले सकते हैं, इसलिए इसे बार-बार कॉल करने की आवश्यकता नहीं है। आप इसे subprocess.check_callos.system
क्लेमेंट

5

UNIX आदेशों में क्या गलत है? (आप विंडोज पर काम नहीं कर रहे हैं):

ls | xargs cat | tee output.txt काम करता है (यदि आप चाहते हैं तो आप इसे सबप्रोसेस के साथ अजगर से कह सकते हैं)


21
क्योंकि यह अजगर के बारे में एक सवाल है।
ऑबस्क्योररोबॉट

2
सामान्य तौर पर कुछ भी गलत नहीं है, लेकिन यह उत्तर टूट गया है (xsgs में ls के आउटपुट को पास न करें, बस सीधे कैट करने के लिए फाइलों की सूची पास करें:) cat * | tee output.txt
क्लेमेंट

अगर यह फ़ाइल नाम भी सम्मिलित कर सकता है जो बहुत अच्छा होगा।
Deqing

@ डाइक इनपुट फ़ाइल नामों को निर्दिष्ट करने के लिए, आप उपयोग कर सकते हैंcat file1.txt file2.txt | tee output.txt
GoTrained

1
... और आप 1> /dev/nullकमांड के अंत में जोड़कर stdout (टर्मिनल में प्रिंटिंग) को भेज सकते हैं
GoTrained

4
outfile.write(infile.read()) # time: 2.1085190773010254s
shutil.copyfileobj(fd, wfd, 1024*1024*10) # time: 0.60599684715271s

एक साधारण बेंचमार्क दर्शाता है कि शटर बेहतर प्रदर्शन करता है।


3

@ इंस्पेक्टरगैजेट उत्तर (दिनांक 29-03-2016 को सर्वश्रेष्ठ उत्तर) का विकल्प। मैंने 436MB की 3 फाइलों के साथ परीक्षण किया।

@ इंस्पेक्टरगैजेट समाधान: 162 सेकंड

निम्नलिखित समाधान: 125 सेकंड

from subprocess import Popen
filenames = ['file1.txt', 'file2.txt', 'file3.txt']
fbatch = open('batch.bat','w')
str ="type "
for f in filenames:
    str+= f + " "
fbatch.write(str + " > file4results.txt")
fbatch.close()
p = Popen("batch.bat", cwd=r"Drive:\Path\to\folder")
stdout, stderr = p.communicate()

"पुरानी अच्छी तकनीक" का लाभ उठाते हुए, एक बैच फ़ाइल बनाने और उस पर अमल करने का विचार है। इसका अर्ध-अजगर लेकिन तेजी से काम करता है। खिड़कियों के लिए काम करता है।


3

यदि आपके पास निर्देशिका में बहुत सारी फाइलें हैं तो glob2हाथ से लिखने के बजाय फ़ाइलनामों की सूची तैयार करने के लिए एक बेहतर विकल्प हो सकता है।

import glob2

filenames = glob2.glob('*.txt')  # list of all .txt files in the directory

with open('outfile.txt', 'w') as f:
    for file in filenames:
        with open(file) as infile:
            f.write(infile.read()+'\n')

2

फ़ाइल ऑब्जेक्ट की .read () विधि देखें:

http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects

आप कुछ ऐसा कर सकते हैं:

concat = ""
for file in files:
    concat += open(file).read()

या अधिक 'सुरुचिपूर्ण' अजगर-तरीका:

concat = ''.join([open(f).read() for f in files])

जो, इस लेख के अनुसार: http://www.skymind.com/~ocrow/python_string/ भी सबसे तेज होगा।


10
यह एक विशाल स्ट्रिंग का उत्पादन करेगा, जो फ़ाइलों के आकार के आधार पर, उपलब्ध मेमोरी से बड़ा हो सकता है। जैसा कि पायथन फाइलों में आसान आलसी पहुंच प्रदान करता है, यह एक बुरा विचार है।
गारेथ लैटी

2

यदि फ़ाइलें विशाल नहीं हैं:

with open('newfile.txt','wb') as newf:
    for filename in list_of_files:
        with open(filename,'rb') as hf:
            newf.write(hf.read())
            # newf.write('\n\n\n')   if you want to introduce
            # some blank lines between the contents of the copied files

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


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

यह सीपीथॉन में कार्यान्वयन है, लेकिन इसकी कोई गारंटी नहीं है। इस तरह का अनुकूलन एक बुरा विचार है क्योंकि यह कुछ प्रणालियों पर प्रभावी हो सकता है, यह दूसरों पर नहीं हो सकता है।
गारेथ लैटी

1
हां, बेशक लाइन-बाय-लाइन पढ़ना बफ़र्ड है। यही कारण है कि यह इतना धीमा नहीं है। (वास्तव में, कुछ मामलों में, यह थोड़ा और भी तेज़ हो सकता है, क्योंकि जिसने भी आपके प्लेटफ़ॉर्म पर पायथन को पोर्ट किया है, उसने 10000 की तुलना में बहुत बेहतर चंक साइज़ चुना है।) यदि यह वास्तव में मायने रखता है, तो आपको अलग-अलग कार्यान्वयन को प्रोफाइल करना होगा। लेकिन 99.99… समय का%, या तो रास्ता तेजी से पर्याप्त से अधिक है, या वास्तविक डिस्क I / O धीमा हिस्सा है और इससे कोई फर्क नहीं पड़ता कि आपका कोड क्या करता है।
ab

इसके अलावा, अगर आपको वास्तव में बफरिंग को मैन्युअल रूप से अनुकूलित करने की आवश्यकता है, तो आप उपयोग करना चाहते हैं os.openऔर os.read, क्योंकि सादे openसी के स्टीडियो के आसपास पायथन के रैपर का उपयोग करता है, जिसका अर्थ है कि आपके रास्ते में 1 या 2 अतिरिक्त बफ़र मिल रहे हैं।
abarnert

PS, क्यों 10000 के लिए बुरा है: आपकी फाइलें संभवतः एक डिस्क पर हैं, उन ब्लॉकों के साथ जो बाइट्स की कुछ शक्ति लंबे हैं। मान लीजिए कि वे 4096 बाइट हैं। तो, 10000 बाइट पढ़ने का मतलब है दो ब्लॉक पढ़ना, फिर अगला भाग। एक और 10000 पढ़ने का मतलब है बाकी अगले भाग को पढ़ना, फिर दो ब्लॉक, फिर अगले हिस्से को पढ़ना। गिनती करें कि आपके पास कितने आंशिक या पूर्ण ब्लॉक हैं, और आप बहुत समय बर्बाद कर रहे हैं। सौभाग्य से, पायथन, stdio, फाइल सिस्टम, और कर्नेल बफरिंग और कैशिंग इन समस्याओं में से अधिकांश को आपसे छिपाएंगे, लेकिन उन्हें पहली जगह में बनाने की कोशिश क्यों करें?
२०

0
def concatFiles():
    path = 'input/'
    files = os.listdir(path)
    for idx, infile in enumerate(files):
        print ("File #" + str(idx) + "  " + infile)
    concat = ''.join([open(path + f).read() for f in files])
    with open("output_concatFile.txt", "w") as fo:
        fo.write(path + concat)

if __name__ == "__main__":
    concatFiles()

-2
  import os
  files=os.listdir()
  print(files)
  print('#',tuple(files))
  name=input('Enter the inclusive file name: ')
  exten=input('Enter the type(extension): ')
  filename=name+'.'+exten
  output_file=open(filename,'w+')
  for i in files:
    print(i)
    j=files.index(i)
    f_j=open(i,'r')
    print(f_j.read())
    for x in f_j:
      outfile.write(x)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.