2016-11-06 5 views
2

이렇게 전에 묻지 않은 것은 흥미 롭습니다.파이썬, 파일의 특정 줄을 비우는 법

파이썬 2의 텍스트 파일에 데이터 행을 기록합니다. 내가 뭘하고 싶은지, 라인의 번호에 의해, 나는 라인을 지우고 싶지만, 다음에 의해 채워지 싶지 않아, 그냥 비어있어 (따라서 새로운 파일을 쓸 필요가 없습니다마다 라인을 삭제합니다.)

그래서 내가 무엇을 해달라고 부탁하는 이들 중 하나가 아닌,

기본 개념은 변경 콩트에 특정 줄의 nts입니다.이 경우 빈 문자열로 변경됩니다.

나는 진정으로 이해하지 못했지만 내 질문에 대한 대답을 포함 할 수있는 질문이 있습니다. 그것이 그렇게되면, 어떻게 그렇게 이해하는지 도와주세요. How to delete a line from a text file using the line number in python

당신은 내 질문이 하나의 중복 생각한다면

  • , 그는 질문을 신고하기 전에, 나에게 대답을 설명해주십시오.

    주제에 내 연구 :

    편집 : 만약 내가 그런 일을하는 걸 잊어 버렸어. 가능한 경우, 귀하의 정보에 감사드립니다.

+1

특정 줄을 공백 문자로 바꾸면 충분합니까? 그렇지 않으면 해당 행 뒤의 모든 바이트를 거꾸로 변환해야합니다. – fuglede

+1

@fuglede 공백 문자로 충분할 것 같아요. 그러나 이제는 동작 이후에 고정 바이트 길이가 필요하다는 것을 알게되었습니다. C 에서처럼. 그러나 각 줄의 길이를 확인하고 충분한 수의 공백으로 바꿀 수 있습니다. 나는 아직도 파이썬에서 그것을 성취하는 방법을 모른다. – Rockybilly

+0

fuglede가 말했듯이, 원하지 않는 바이트를 공백 문자로 대체 할 수 있습니다 (예 : 공백 문자 (ASCII 코드 0x20)). 전통적으로 이러한 목적으로 [DEL 문자] (https://en.wikipedia.org/wiki/Delete_character) (ASCII 코드 0x7f)가 사용되었습니다. –

답변

0

너는 무엇을하고 있니?

def remove_line_from_file(filename, line_number): 
    with open(filename) as f: 
     lines = f.readlines() 
    lines[line_number - 1] = '\n' # <- or whatever kind of newline is relevant for your system 
    with open(filename, 'w') as f: 
     f.writelines(lines) 

그런 다음 파일 test의 내용이있는 경우

line 1 
line 2 
line 3 

remove_line_from_file('test', 2)을 실행하는 것은 실제로 질문을 제대로 읽어 지금,

line 1 

line 3 

업데이트로 test을 설정합니다 :이 방법을 줄의 내용을 공백 문자로 바꾸어 파일을 수정합니다.

def remove_line_from_file(filename, line_number): 
    with open(filename, 'r+') as f: 
     count = 0 
     bytes_read = 0 
     while True: 
      bytes_read += 1 
      this_byte = f.read(1) 
      if not this_byte: 
       break 
      if this_byte == '\n': 
       count += 1 
       if count == line_number - 1: 
        start = bytes_read 
       elif count == line_number: 
        f.seek(start) 
        f.write(' ' * (bytes_read - start - 1)) 
        break 

위의 PM 2Ring의 의견에 따르면, ' ' 대신 chr(127)을 사용하는 것이 좋습니다.fileinput 컨텍스트 관리자 (with 문)를 지원하고, 새로운 print() 기능이 우리를 수 있습니다 : 파이썬 3는 여기에 몇 가지 장점을 가지고

import fileinput 
def blank_line(filename, lineno): 
    f = fileinput.input(files=[filename], inplace=True) 
    for line in f: 
     if fileinput.lineno() == lineno: # note: line numbers start at 1, not 0 
      line = "" 
     print line.rstrip("\n") # Output is redirected to the current line of the file 
    f.close() 

참고 :

+1

답변 해 주셔서 감사합니다. 귀하의 접근 방식은 효과가 있지만, 이것은 정확히 내가 피하려고하는 것입니다. 모든 데이터를 읽고 모두 함께 쓰십시오. – Rockybilly

+0

아, 죄송합니다. 질문에 그 부분이 빠졌습니다. 실제로,'file.seek'는 여러분이 그 후인 것입니다. https://stackoverflow.com/questions/1877999/delete-final-line-in-file-via-python/10289740#10289740 그 라인을 따라 무언가를합니다 (그러나 최종 라인에만 적용됨). 바로). – fuglede

+0

DEL char을 사용하면 Python 스크립트 나 표준 * nix'tr' 유틸리티를 사용하여 파일을 신속하게 "압축하여"파일을 복사하고 모든 DEL을 제거 할 수 있다는 이점이 있습니다. –

0

당신은 맞다는 fileinput module하실 것을 적극 (줄 바꿈 또는 끝 부분에 항상 공백을 추가하는 대신) 그대로 줄을 보존합니다.

+0

그러나 OP는 "선을 지울 때마다 새 파일을 쓰고 싶지 않다"고 말합니다. 그들은 지우고 싶은 한 줄만 수정하기를 원합니다. –

+0

메모리가 아닌 CPU주기를 저장하고 싶습니다.나는 어떤 시점 이후 라인이 증가함에 따라 파일을 정리할 것입니다. – Rockybilly

0

대부분의 시스템에있는 텍스트 파일이 디스크 또는 다른 저장 매체에 저장되는 방식을 이해해야합니다.

서로 다른 시스템간에 세부 사항은 다소 차이가 있지만 오늘날에는 모두 고정 된 크기의 "블록"개념을 사용합니다. 파일은 해당 블록에 할당되며 텍스트 파일은 일부 문자가 0x0A 개행 코드 (*) 인 일련의 문자입니다.

예를 들어 블록이 32 바이트라고 가정 해 봅니다 (일반적으로 블록이 더 큽니다. 그러나 다이어그램을 읽기 쉽게 만들기 위해).

_______text file logical content________ 
|Hello, world¶       | 
|This is a text file that contains¶  | 
|three lines¶____________________________| 

_______________________a 32 bytes block______________________ 
|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| 
|H|e|l|l|o|,| |w|o|r|l|d|.|¶|T|h|i|s| |i|s| |a| |t|e|x|t| |f|i| 
|l|e| |t|h|a|t| |c|o|n|t|a|i|n|s|¶|t|h|r|e|e| |l|i|n|e|s|¶|_|_| 

세 줄은 두 개의 블록을 차지하며 두 번째 블록의 마지막 두 바이트는 사용되지 않습니다.

파일 시스템은 여분의 2 바이트를 표시하지 않지만 중요한 점은 텍스트 파일의 "lines"이 디스크의 파일 구조에 을 수행하지 않는다는 것입니다. 모든 행은 다음과 같습니다. (**) 사이에 특별한 개행 문자가 연속적으로 기록됩니다.

예를 들어, 동일한 길이의 다른 라인으로 바꾸려면 몇 바이트 만 업데이트하면됩니다. 대신 라인의 길이가 다른 경우 또는 새 라인을 삭제하거나 삽입하려는 경우 유일한 해결책은 실제로 전체 파일을 해당 지점에서 끝까지 다시 작성하는 것입니다.

(*) 리틀 여담 : MS-DOS는 오래 전에 사용하고 이제부터는 윈도우 음 ... 아무도 확실히 알지 못한다 ... 때문에 뉴 라인 마킹 0x0D + 0x0A 오늘 문자를 사용 : 그것은 바보 어리석은 어리석은 형언 할 수없는 심지어 평범한 이유없이 우리 모두는 영원히 살아야합니다. 두 개의 개행 문자가있는 실수는 "바이너리 모드"광기의 근원입니다.

(**) 두 번째 문제 : 텍스트 파일에 줄 끝 문자를 사용하는 대신 고정 길이 줄이있는 오늘날에도 매우 일반적인 "파일 시스템"이 있지만 은행 계좌, 보험 증서 및 소스 코드가 오래 전에 잃어버린 COBOL 프로그램에 의해 끊임없이 뒤섞이는 절대적으로 중요한 정보이며 어쨌든 심각한 저장소를 유지 한 사람은 아무도 없습니다. 이 두려운 경우에 그 (것)들을 다만 무시하고 매트리스의 밑에 당신의 돈 전부를 지키십시오.

+0

필자가 필요로하는 것은 파이썬의 링크리스트 equivelant이다 (하지만 여전히 하드 디스크에 파일로 저장되어있다). 내가 사용할 구조가 바로 양키 (deque)이기 때문입니다. 운영 체제에 이러한 데이터 유형이 있는지 궁금합니다. – Rockybilly

3

여기에는 텍스트 파일을 제자리에서 수정하여 지정된 줄을 동일한 길이의 줄로 바꾸는 기능이 있습니다.

이 데모에서는 대체 문자로 #을 사용하여 어떤 일이 일어나는지 쉽게 확인합니다. 대신 간단한 공간 (chr(32)) 또는 ASCII DEL 문자 (chr(127) == \x7f)를 사용할 수 있습니다. DEL을 사용하면 파일의 "적절한"행에 문자가 나타나지 않기 때문에 모든 "지워진"행을 빠르게 삭제하는 것이 더 쉽습니다.

첫째, 여기에이 코드를 테스트 할 수있는 작은 텍스트 파일이 있습니다.

qdata

1 one 
2 two 
3 three 
4 four 
5 five 
6 six 
7 seven 
8 eight 
9 nine 

여기에 코드입니다. 1에서 시작하는 줄 번호 매기기를 사용합니다. 여기

def erase_line(fname, line_num): 
    ''' In-place replacement of line `line_num` in file `fname` with 
     a line of DEL chars of the same length, retaining the newline. 
    ''' 
    DEL = '#' 
    with open(fname, 'r+') as f: 
     for i in range(line_num - 1): 
      f.readline() 
     start = f.tell() 
     line = f.readline() 
     line = DEL * (len(line) - 1) + '\n' 
     f.seek(start) 
     f.write(line) 

erase_line('qdata', 3) 

qdata의 수정 된 버전입니다 :
1 one 
2 two 
####### 
4 four 
5 five 
6 six 
7 seven 
8 eight 
9 nine 

는 다양한 길이의 라인을 처리해야하기 때문에

erase_line이 원하는 하나를 찾을 때까지 모든 라인을 읽을 수있다하지만, 그것은 단지 그 라인을 다시 쓰고, 다른 라인들은 수정하지 않기 때문에, 그것은 꽤 빠르다. 줄의 길이가 고정 된 경우 .skip을 사용하여 원하는 줄로 바로 이동할 수 있습니다.


다음은 완전히 DEL 문자로 구성된 모든 행을 제거하고 결과를 새 파일에 쓰는 기능입니다.

def compact(oldname, newname): 
    ''' Copy file `oldname` to `newname`, removing lines that 
     consist entirely of the DEL char, apart from the '\n' 
    ''' 
    DEL = '#' 
    with open(oldname, 'r') as fin, open(newname, 'w') as fout: 
     for line in fin: 
      if not line.lstrip(DEL) == '\n': 
       fout.write(line) 

compact('qdata', 'qdata.new') 

qdata.new

1 one 
2 two 
4 four 
5 five 
6 six 
7 seven 
8 eight 
9 nine 

마지막으로, 여기에 당신이 (8 진수 \177입니다) 실제 DEL 문자를 사용하는 가정의 성형 작업을 수행하는 유닉스/리눅스 파이프 라인입니다. 파이썬 버전보다 빠르다.

tr -d '\177' <qdata | awk '!/^$/' >qdata.new 
관련 문제