방금 큰(기가바이트) 크기의 파일에서 일부 줄을 잘라야 하는 문제에 부딪혔고, 메모리에서 파일을 읽으려고 할 때 CPU 사용량이 발생할 수 있다는 것을 깨닫고 그 자리에서 편집하고 싶었습니다... ... 그래서 다음과 같은 문제가 발생했습니다.
...그리고 이것들은:
ext3
그러나 나는 다른 것에 대해 생각하고 있습니다. 나는 모든 파일 시스템(예 : )이 디스크 영역에 매핑된 파일 조각과 같은 것을 설명할 수 있도록 연결된 목록과 같은 것을 사용해야 한다고 믿습니다(그러나 확실하지 않습니다). .
따라서 다음과 같은 작업을 수행하는 것이 가능해야 합니다. 예를 들어 다음과 같은 파일이 있다고 가정해 보겠습니다 bigfile.dat
(숫자는 바이트 오프셋을 나타내야 하지만 이를 정렬하는 것은 약간 어렵습니다).
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
L 1\n L 2\n L 3\n L 4\n L 5\n L 6\n
원칙적으로, 검색을 위해 파일을 터미널 애플리케이션에 로드할 수 있습니다. 도구를 호출한다고 가정하고 동일한 파일(줄 번호 포함)이 표시되는 방식 editsegments bigfile.dat
과 비슷하다고 가정해 보겠습니다 .less -N bigfile.dat
1 1 L 1
2 2 L 2 *
3 3 L 3
4 4 L 4 *
5 5 L 5
6 6 L 6
bigfile.dat (END)
거기에 명령(예: 행 삭제)을 입력하고 d
다른 키나 마우스를 클릭하면 *
행 2와 행 4 사이의 모든 항목이 삭제되어야 한다는 메시지가 표시된다고 가정해 보겠습니다. 그러면 프로그램이 응답하고 다음을 표시합니다.
1 1 L 1
2 5 L 5
3 6 L 6
bigfile.dat (END)
이제 가장 왼쪽의 첫 번째 열에는 "새" 행 번호(잘라내기 전)가 표시되고, 두 번째 열에는 "이전" 행 번호(잘라내기 전)가 표시되며, 그 다음에는 실제 행 내용이 표시됩니다.
이제 이 가짜 애플리케이션이 종료된 후 어떤 일이 일어날지 상상해 보세요. editsegments
무엇보다도 bigfile.dat
영향을 받지 않습니다. 그러나 이제 동일한 디렉터리에 bigfile.dat.segments
다음 내용을 포함하는 추가 텍스트 파일이 있게 됩니다.
d 4:15 # line 2-4
bigfile.dat.iedit
...또한, "symlink"와 같은 특수 파일이 나타납니다. 이를 "it"이라고 부르겠습니다.
bigfile.dat.iedit
이제 기본적으로 이 모든 것의 결과는 다음과 같이 지금 열려고 하면 다음과 같습니다 less -N bigfile.dat.iedit
. "편집된" 콘텐츠를 가져오고 싶습니다.
1 L 1
2 L 5
3 L 6
bigfile.dat (END)
...이것은 OS에 어떤 방식으로든 지시하여 $FILE.iedit
열 때 먼저 $FILE.segments
열어서 d 4:15
원본 파일의 바이트 4~15를 생략해야 함을 나타내도록 하면 달성할 수 있습니다. 그러면 다음과 같은 결과가 발생합니다. 다음에 대한 결과:
0 1 2 3 4 5 6 7 8 9 10 11 12,3,4 15 16 17 18 19 20 21 22 23
L 1\n
L
2
\n
L
3
\n
L
4
\n
L 5\n
L 6\n
0 1 2 3---------------------------------- -->16 17 18 19 20 21 22 23
다시 말해서 -가설파일 시스템 개념에서 콘텐츠의 각 바이트에는 체인의 다음 바이트에 대한 "링크"도 포함됩니다. 파일 시스템에 스크립트를 기반으로 새 연결 목록을 구축하고 다음과 같이 콘텐츠를 제공하도록 지시할 수 있어야 합니다. 수정된 연결 목록으로 표시되는 특수 파일(심볼릭 링크 또는 파이프).
이것이 제목에서 "스크립팅 가능"하다는 의미입니다. "새" 연결 목록은 $FILE.segments
사용자가 텍스트 편집기에서 편집할 수 있는(또는 프런트 엔드 애플리케이션에서 생성할 수 있는) 스크립트 파일( )에 의해 제어될 수 있습니다. "여러 번"이라는 것은 bigfile.dat
프로세스 중에 전혀 수정하지 않음을 의미합니다 . 따라서 오늘 첫 번째(원본) 기가바이트를 편집하고 진행 상황을 ( $FILE.segments
)에 저장할 수 있습니다. 그런 다음 내일 두 번째 기가바이트를 편집하고 진행 상황을 ( $FILE.segments
) 다시 등 - 원래 내용은 변경되지 않은 채로 bigfile.dat
유지됩니다.
editsegments --finalize bigfile.dat
모든 편집이 완료되면 새로운 연결 목록을 의 내용으로 영구적으로 인코딩하는 일종의 명령(예: )을 호출할 수 있습니다 bigfile.dat
(그리고 이에 따라 bigfile.dat.segments
및 를 제거 bigfile.dat.iedit
). 또는 더 간단하게는 다음과 같이 할 수 있습니다.
cp bigfile.dat.iedit /path/to/somewhere/else/bigfile.modified.dat
물론 d
elete 스크립트 명령 외에도 r
eplace 명령도 있을 수 있습니다. 예를 들면 다음과 같습니다.
r 16:18 AAA
...설명: 바이트 16과 18 사이의 내용을 공백 뒤의 다음 18-16+1=3바이트로 바꾸십시오(예: AAA
). 연결된 목록은 실제로 스크립트 명령 내용 자체에 "연결"될 수 있습니다(그림 아래도 엘레테 포함 d
):
0 1 2 3 4 5 6 7 8 9 10 11 12,3,4 15 16 17 18 19 20 21 22 23
L 1\n
L
2
\n
L
3
\n
L
4
\n
L
5
\n
L 6\n
0 1 2 3---------------------------------- -->| 19 20 21 22 23
.
.
.
.
.
.
.
\n
r
1
6
:
1
8
AAA
\n
.
.
.
.
이제 나는 프로그램이 hexedit
(위에서 언급한 바와 같이) 다음과 같기를 원합니다.여기)은 파일을 그 자리에서 변경합니다. 하지만 저는 스크립팅 가능성의 이점(터미널 응용 프로그램이라도 GUI 응용 프로그램으로 관리할 수 있다면 더 좋을 것입니다)과 실제로 원본 파일이 없다는 이점이 마음에 듭니다. 변경, 모든 편집 내용이 준수되는 것으로 확인될 때까지.
그런 일이 가능한지 잘 모르겠습니다. 설사 가능하더라도 (단순한 사용자 프로그램이 아닌) 전용 드라이버가 필요할 수도 있다고 생각합니다... 하지만 어쨌든 물어볼 가치가 있다고 생각합니다. Linux 거기에 비슷한 것이 있나요?
답변해 주셔서 대단히 감사합니다.
응원합니다!
답변1
디스크의 파일 구조는 사용되는 파일 시스템에 따라 다릅니다. 실제 파일 시스템에서는 귀하가 설명하는 것과 같은 연결 목록을 사용하지 않습니다( fseek(3)
견딜 수 없는 일입니다). 이에 가장 가까운 것은 Microsoft의 것입니다.지방, 기본적으로 데이터 블록의 포인터를 배열로 이동하여 숨깁니다.
그러나 대부분의 파일 시스템은 파일의 데이터 블록에 대한 일부 포인터 기반 참조를 사용하므로 원칙적으로 전체 파일 내용이 아닌 소수의 포인터를 뒤섞고 블록을 표시하여 파일을 잘라낼 수 있습니다. 블록의 파일. 파일의 중간 부분은 무료입니다. 불행하게도 이것은 매우 유용한 작업이 아닙니다. 파일 블록은 상당히 크고(일반적으로 4KiB) 파일의 구조(라인 또는 기타 하위 구분)와 합리적으로 잘 정렬되는 경우는 거의 없습니다.
답변2
당신이 묘사하는 것은 매우 비슷해 보입니다.다시 하다텍스트 편집기다시 실행 목록변경되지 않은 원본 파일의 경우다시 실행 목록gvim
나는 하나가 있다고 확신합니다.지속성 있는실행 취소/다시 실행 목록, 이를 활용(?)할 수 있으며, emacs
그러한 목록이 확실히 있다는 것을 알고 있습니다. 스크립트를 통해 원하는 대로 수행하도록 동축할 수 있습니다 elisp
.세션 간 Emacs 실행 취소 기록 저장.
그런데, 이렇게 큰 파일이 있으면 다음과 같은 불필요한 작업을 모두 끄는 것이 좋습니다.자동 저장,구문 강조(천천히 해큰emacs 파일) 등, 32비트 시스템의 emacs는 256MB입니다.파일 크기 제한.
제안한 것만큼 간결하지는 않지만 많은 변경 없이는 유용할 수 있습니다.
답변3
일반적으로 전체 파일을 메모리에 넣지 않으면 파일을 내부에서 편집할 수 없습니다. 나는 당신이 정말로 원하는 것은 특정 줄이 없는 이전 파일의 복사본인 새 파일을 갖는 것이라고 가정합니다. 이는 유닉스 유틸리티를 사용하여 head
쉽게 수행할 수 있습니다 tail
. 예를 들어, 파일에서 5, 12, 52행을 제외한 모든 내용을 복사하려면 다음을 수행합니다.
head -n 4 bigfile.dat > tempfile.dat
tail -n +6 bigfile.dat | head -n 6 >> tempfile.dat
tail -n +13 bigfile.dat | head -n 39 >> tempfile.dat
tail -n 53 bigfile.dat >> tempfile.dat
이러한 유틸리티에 대해 잘 모르신다면 더 자세히 설명하겠습니다.
이 head
유틸리티는 파일의 처음 n줄을 인쇄합니다. 위치 인수가 제공되지 않으면 표준 입력을 파일로 사용합니다. 이 -n
플래그는 인쇄할 라인 수를 헤드에 알려줍니다. 따라서 head -n 2
표준 입력의 처음 두 줄만 인쇄됩니다.
이 tail
유틸리티는 파일의 마지막 n줄을 인쇄합니다. head와 마찬가지로 파일이나 표준 입력에서 읽을 수 있습니다. -n 플래그는 tail 끝부터 인쇄할 줄 수를 알려줍니다. 숫자 앞에 더하기 기호를 추가하여 tail이 처음부터 많은 줄을 파일 끝부터 인쇄하도록 할 수도 있습니다. 예를 들어 tail -n 2
표준 입력의 마지막 두 줄을 인쇄합니다. 그러나 tail -n +2
2행부터 시작하는 모든 행이 인쇄됩니다(1행은 생략됨).
따라서 일반적으로 파일에서 [x, y) 범위의 행을 인쇄하려면 다음을 수행하십시오.
`tail -n +x | head -n d`
여기서 d = y - x입니다. 이 명령은 새 파일을 생성합니다. 원하는 경우 오래된 파일을 삭제할 수 있습니다. 이것의 장점은 한 번에 한 행만 메모리에 유지하면 되므로 RAM이 매우 빨리 채워지지 않는다는 것입니다 head
.tail
답변4
sed 스크립트 작업처럼 들립니다. IIRC는 이러한 유형의 작업을 위해 설계되었습니다. 라인별 처리, 동일한 명령 집합의 반복 처리, 정규 표현식이 모두 하나의 도구에 결합되어 있습니다. 나는 그것이 일을 할 것이라는 것을 알고 있지만, 당신의 작업을 안내하는 것 이상으로 당신을 안내할 수는 없습니다.매뉴얼 페이지.