2009-12-28 7 views
18

두 개의 텍스트 파일, Source.txt 및 Target.txt가 있습니다. 원본은 수정되지 않으며 N 줄의 텍스트가 포함됩니다. 그래서, Target.txt 텍스트의 특정 줄을 삭제하고 Source.txt 텍스트의 특정 줄 바꾸고 싶습니다, 실제로 필요한 줄 수를 알고 실제로 두 줄 번호 2, 두 파일입니다.C에서 텍스트 파일의 특정 줄 편집

I 피난처이 같은 :

string line = string.Empty; 
int line_number = 1; 
int line_to_edit = 2; 

using (StreamReader reader = new StreamReader(@"C:\source.xml")) 
{ 
    using (StreamWriter writer = new StreamWriter(@"C:\target.xml")) 
    { 
     while ((line = reader.ReadLine()) != null) 
     { 
      if (line_number == line_to_edit) 
      { 
       writer.WriteLine(line); 
      } 

      line_number++; 
     } 
    } 
} 

하지만 라이터를 열 때, 대상 파일이 삭제 얻을, 그것은 선을 기록하지만, 열 때, 대상 파일은 복사 한 줄이 포함는 나머지는 길을 잃는다.

어떻게해야합니까?

답변

38

줄이 같은 길이가 아닌 한 전체 파일을 다시 쓰지 않고 줄을 다시 쓸 수는 없습니다. 파일이 작 으면 전체 대상 파일을 메모리로 읽은 다음 다시 쓰는 것이 좋습니다. 이 같은이 작업을 수행 할 수 있습니다

using System; 
using System.IO; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     int line_to_edit = 2; // Warning: 1-based indexing! 
     string sourceFile = "source.txt"; 
     string destinationFile = "target.txt"; 

     // Read the appropriate line from the file. 
     string lineToWrite = null; 
     using (StreamReader reader = new StreamReader(sourceFile)) 
     { 
      for (int i = 1; i <= line_to_edit; ++i) 
       lineToWrite = reader.ReadLine(); 
     } 

     if (lineToWrite == null) 
      throw new InvalidDataException("Line does not exist in " + sourceFile); 

     // Read the old file. 
     string[] lines = File.ReadAllLines(destinationFile); 

     // Write the new file over the old file. 
     using (StreamWriter writer = new StreamWriter(destinationFile)) 
     { 
      for (int currentLine = 1; currentLine <= lines.Length; ++currentLine) 
      { 
       if (currentLine == line_to_edit) 
       { 
        writer.WriteLine(lineToWrite); 
       } 
       else 
       { 
        writer.WriteLine(lines[currentLine - 1]); 
       } 
      } 
     } 
    } 
} 

을 파일은 당신이 당신에 다른 쓰기 동안 하나 개의 파일에서 스트리밍 읽을 수 있도록 새 파일을 만들 좋을 것이다 큰 경우. 즉, 한 번에 전체 파일을 메모리에 저장할 필요가 없습니다. 이 같은이 작업을 수행 할 수 있습니다 당신은 쓰기 작업이 성공 확신합니다 (더 excecption가 발생되지 않았으며 작가가 닫혀) 일단

using System; 
using System.IO; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     int line_to_edit = 2; 
     string sourceFile = "source.txt"; 
     string destinationFile = "target.txt"; 
     string tempFile = "target2.txt"; 

     // Read the appropriate line from the file. 
     string lineToWrite = null; 
     using (StreamReader reader = new StreamReader(sourceFile)) 
     { 
      for (int i = 1; i <= line_to_edit; ++i) 
       lineToWrite = reader.ReadLine(); 
     } 

     if (lineToWrite == null) 
      throw new InvalidDataException("Line does not exist in " + sourceFile); 

     // Read from the target file and write to a new file. 
     int line_number = 1; 
     string line = null; 
     using (StreamReader reader = new StreamReader(destinationFile)) 
     using (StreamWriter writer = new StreamWriter(tempFile)) 
     { 
      while ((line = reader.ReadLine()) != null) 
      { 
       if (line_number == line_to_edit) 
       { 
        writer.WriteLine(lineToWrite); 
       } 
       else 
       { 
        writer.WriteLine(line); 
       } 
       line_number++; 
      } 
     } 

     // TODO: Delete the old file and replace it with the new file here. 
    } 
} 

당신은 나중에 파일을 이동할 수 있습니다.

두 경우 모두 라인 번호에 대해 1 기반 색인을 사용하는 것이 다소 혼란 스럽습니다. 코드에서 0 기반 인덱싱을 사용하는 것이 더 적합 할 수 있습니다. 원하는 경우 사용자 인터페이스에서 프로그램에 대한 1부터 시작하는 인덱스를 가질 수 있지만 추가로 보내기 전에 0으로 인덱싱 된 인덱스로 변환 할 수 있습니다.

이전 파일을 새 파일로 직접 덮어 쓰는 단점은 중간에 오류가 발생하면 기록되지 않은 데이터가 영구적으로 손실 될 수 있다는 것입니다. 세 번째 파일에 쓰기를하면 다른 (수정 된) 복사본이 있다는 것을 확인한 후에 만 ​​원래 데이터가 삭제되므로 컴퓨터가 중간에 충돌 한 경우 데이터를 복구 할 수 있습니다.

마지막 설명 : 파일 확장명이 xml 인 것으로 나타났습니다. XML 파서를 사용하여 특정 줄을 바꾸는 대신 파일의 내용을 수정하는 것이 더 합리적인지 고려해 볼 수 있습니다.

2

StreamWriter을 만들 때 항상 파일을 처음부터 만들면 대상에서 세 번째 파일을 만들고 복사하여 필요한 것을 바꾼 다음 이전 파일을 바꿔야합니다. 그러나 XML 조작이 필요한지 알 수 있으므로 XmlDocument을 사용하고 Xpath를 사용하여 파일을 수정해야 할 수 있습니다.

1

아래 예제가 작동해야한다고 생각합니다 (예제의 작성자 부분 대신). 그것은 메모리에서 그래서 나는 어떤 빌드 환경 불행하게도 해요하지만 난 당신이 아니라 항상 출력 파일을 덮어 쓰는 새에서는 StreamReader를 사용하는 것보다 쓰기 액세스에 대한 출력 파일을 열 필요가

using (var fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite))) 
     { 
      var destinationReader = StreamReader(fs); 
      var writer = StreamWriter(fs); 
      while ((line = reader.ReadLine()) != null) 
      { 
       if (line_number == line_to_edit) 
       { 
        writer.WriteLine(lineToWrite); 
       } 
       else 
       { 
        destinationReader .ReadLine(); 
       } 
       line_number++; 
      } 
     } 
2

도움이되기를 바랍니다.

물론
StreamWriter stm = null; 
fi = new FileInfo(@"C:\target.xml"); 
if (fi.Exists) 
    stm = fi.OpenWrite(); 

, 당신은 여전히 ​​당신이 이미 알고하지 않는 바이트가 추구하는 오프셋, 그래서 당신이 그것을 읽을 수 없기 때문에 힘들 것입니다 출력 파일에 올바른 선을 추구해야 할 것이다, 아마 당신은 정말로 읽기/쓰기 접근을 원할 것입니다.

FileStream stm = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); 

이 스트림에서는 변경하려는 지점에 도달 할 때까지 읽을 수 있습니다. 행이 아닌 바이트를 쓰고 있으므로 행을 겹쳐 쓰려면 변경하려는 행과 동일한 문자 수를 써야합니다.

21

가장 쉬운 방법은 다음과 같습니다

static void lineChanger(string newText, string fileName, int line_to_edit) 
{ 
    string[] arrLine = File.ReadAllLines(fileName); 
    arrLine[line_to_edit - 1] = newText; 
    File.WriteAllLines(fileName, arrLine); 
} 

사용 :

lineChanger("new content for this line" , "sample.text" , 34); 
+0

물론 브릴리언트 대답 !! ... 완전히 여기서 일하는. 도트 네트 2.0에서 실행 중입니다 ... Unity3d에서 ___ function lineChanger (newText : String, fileName : String, line_to_edit : int) { var arrLine : String [] = File.ReadAllLines (fileName); arrLine [line_to_edit-1] = newText; File.WriteAllLines (fileName, arrLine); } –

+0

전체 파일을 다시 씁니다. –

+0

또한 전체 파일을 한 번에 메모리에로드합니다. 하지만 아마도 가장 쉬운 접근 방법이며 작은 파일에서도 계속 사용할 수 있습니다. –

관련 문제