簡體   English   中英

使用python將特定行從一個文件寫入另一個文件

[英]Using python to write specific lines from one file to another file

我有~200個短文本文件(50kb),它們都有類似的格式。 我想在每個包含特定字符串的文件中找到一行,然后將該行加上接下來的三行(但不是文件中的其余行)寫入另一個文本文件。 我正在嘗試自學python以便做到這一點,並編寫了一個非常簡單粗暴的小腳本來試試這個。 我使用的是2.6.5版,並從Mac終端運行腳本:

#!/usr/bin/env python

f = open('Test.txt')

Lines=f.readlines()
searchquery = 'am\n'
i=0

while i < 500:
    if Lines[i] == searchquery:
        print Lines[i:i+3]
        i = i+1
    else:
        i = i+1
f.close()

這或多或少有效並將輸出打印到屏幕上。 但我想將行打印到一個新文件,所以我試過這樣的事情:

f1 = open('Test.txt')
f2 = open('Output.txt', 'a')

Lines=f1.readlines()
searchquery = 'am\n'
i=0

while i < 500:
if Lines[i] == searchquery:
    f2.write(Lines[i])
    f2.write(Lines[i+1])
    f2.write(Lines[i+2])
    i = i+1
else:
    i = i+1
f1.close()
f2.close()

但是,沒有任何內容寫入文件。 我也試過了

from __future__ import print_function
print(Lines[i], file='Output.txt')

而且也無法讓它發揮作用。 如果有人能夠解釋我做錯了什么或提出一些關於我應該嘗試的建議,我將非常感激。 此外,如果您有任何建議使搜索更好,我也會很感激。 我一直在使用一個測試文件,其中我想要找到的字符串是該行上唯一的文本,但在我的真實文件中,我需要的字符串仍然在行的開頭,但后面是一堆其他文本,所以我認為我現在設置的方式也不會真正起作用。

謝謝,對不起,如果這是一個超級基本的問題!

正如@ajon指出的那樣,除了縮進之外,我認為你的代碼沒有任何根本性的錯誤。 隨着縮進修復它對我有用。 然而,有幾個改進的機會。

1)在Python中,迭代事物的標准方法是使用for循環 使用for循環時,您不需要定義循環計數器變量並自己跟蹤它們以迭代事物。 相反,你寫這樣的東西

for line in lines:
    print line

迭代字符串列表中的所有項目並打印它們。

2)在大多數情況下,這就是你的for循環的樣子。 但是,在某些情況下,您確實希望跟蹤循環計數。 您的情況就是這種情況,因為您不僅需要一行而且需要接下來的三行,因此需要使用計數器進行索引( lst[i] )。 對於有enumerate()將返回的項目清單價格指數比,你可以再循環。

for i, line in enumerate(lines):
    print i
    print line
    print lines[i+7]

如果您要像示例中那樣手動跟蹤循環計數器,則有兩件事:

3) i = i+1應該移出ifelse塊。 你在兩種情況下都這樣做,所以把它放在if/else 在你的情況下, else塊不再做任何事情,可以消除:

while i < 500:
    if Lines[i] == searchquery:
        f2.write(Lines[i])
        f2.write(Lines[i+1])
        f2.write(Lines[i+2])
    i = i+1

4)現在,這將導致IndexError的文件短於500行。 您應該使用要迭代的序列的實際長度,而不是將循環計數硬編碼為500。 len(lines)會給你那個長度。 但是不使用while循環,而是使用for循環和range(len(lst))迭代范圍從0到len(lst) - 1

for i in range(len(lst)):
    print lst[i]

5) open()可以用作上下文管理器 ,負責為您關閉文件。 上下文管理器是一個相當先進的概念,但如果它們已經為您提供,則使用它們非常簡單。 通過做這樣的事情

with open('test.txt') as f:
    f.write('foo')

該文件將被打開,並作為訪問你f里面是with塊。 離開塊后,文件將自動關閉,因此您最終忘記關閉文件。

在你的情況下,你打開兩個文件。 這可以通過使用兩個with語句並嵌套它們來完成

with open('one.txt') as f1:
    with open('two.txt') as f2:
        f1.write('foo')
        f2.write('bar')

或者,在Python 2.7 / Python 3.x中,通過在單個with語句中嵌套兩個上下文管理器:

    with open('one.txt') as f1, open('two.txt', 'a') as f2:
        f1.write('foo')
        f2.write('bar')

6)根據創建文件的操作系統,行結尾不同。 在類UNIX平台是\\n ,蘋果OS X使用前\\r ,和Windows使用\\r\\n 因此,對於Mac或Windows行結尾, Lines[i] == searchquery將不匹配。 file.readline()可以處理所有三個,但因為它保留了行尾的任何行結尾,所以比較將失敗。 這是通過使用str.strip()解決的, str.strip()將在開頭和結尾處str.strip()所有空格的字符串,並比較沒有行結束的搜索模式:

searchquery = 'am'
# ...
            if line.strip() == searchquery:
                # ...

(使用file.read()讀取文件並使用str.splitlines()將是另一種選擇。)

但是,既然你提到你的搜索字符串實際出現在行的開頭,那么讓我們使用str.startswith()

if line.startswith(searchquery):
    # ...

7) Python的官方樣式指南, PEP8 ,建議使用CamelCase用於類, lowercase_underscore用於其他所有內容(變量,函數,屬性,方法,模塊,包)。 因此,而不是Lines使用lines 與其他人相比,這絕對是一個小問題,但仍值得盡早開始。


所以,考慮到所有這些事情我會寫這樣的代碼:

searchquery = 'am'

with open('Test.txt') as f1:
    with open('Output.txt', 'a') as f2:
        lines = f1.readlines()
        for i, line in enumerate(lines):
            if line.startswith(searchquery):
                f2.write(line)
                f2.write(lines[i + 1])
                f2.write(lines[i + 2])

正如@TomK指出的那樣,所有這些代碼都假設如果你的搜索字符串匹配,那么它后面至少有兩行。 如果你不能依賴這個假設,那么通過使用try...except處理那個案例, try...except @poorsod建議的塊try...except是正確的方法。

我認為你的問題是底部文件的標簽。

你需要縮進if Lines[i]直到i=i+1例如:

while i < 500:
    if Lines[i] == searchquery:
        f2.write(Lines[i])
        f2.write(Lines[i+1])
        f2.write(Lines[i+2])
        i = i+1
    else:
        i = i+1

ajon有正確的答案,但只要您正在尋找指導,您的解決方案就不會利用Python可以提供的高級構造。 怎么樣:

searchquery = 'am\n'

with open('Test.txt') as f1:
  with open(Output.txt, 'a') as f2:

    Lines = f1.readlines()

    try:
      i = Lines.index(searchquery)
      for iline in range(i, i+3):
        f2.write(Lines[iline])
    except:
      print "not in file"

即使發生異常,兩個“with”語句也會自動關閉文件的末尾。

一個更好的解決方案是避免一次讀取整個文件(誰知道它有多大?),而是逐行處理,使用文件對象的迭代:

  with open('Test.txt') as f1:
    with open(Output.txt, 'a') as f2:
      for line in f1:
        if line == searchquery:
          f2.write(line)
          f2.write(f1.next())
          f2.write(f1.next())

所有這些都假設您的目標線之外至少還有兩條線。

您是否嘗試使用“Output.txt”以外的其他內容來避免任何與文件系統相關的問題?

如何在診斷時避免任何時髦無法預料的問題。

這個建議只是從診斷的角度出發。 另請查看OS X dtrace和dtruss。

請參閱: mac os X上的strace -feopen <command>的等效項

使用大數據時,逐行寫入可能會很慢。 您可以通過一次讀/寫一堆行來加速讀/寫操作。

from itertools import slice

f1 = open('Test.txt')
f2 = open('Output.txt', 'a')

bunch = 500
lines = list(islice(f1, bunch)) 
f2.writelines(lines)

f1.close()
f2.close()

如果您的線路太長並且取決於您的系統,您可能無法在列表中放置500行。 如果是這種情況,您應該減少bunch大小並根據需要執行盡可能多的讀/寫步驟來編寫整個內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM