2012-03-09 2 views
3

파일의 마지막 x 줄을 제외한 모든 내용을 C#의 streamreader로 읽어야합니다. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?streamreader에서 마지막 x 줄을 제거하십시오.

많은 감사!

+2

x 줄 바꿈에 대한 파일의 끝에서부터 읽은 다음 파일의 처음부터 그 위치까지 읽습니다. –

+0

파일에서 읽으려고하는 레코드에 일정한 일관성이 있습니까 (일반 레코드 길이,'\ n'으로 끝나는 것 이외의 다른 것)? –

답변

3

를가 큰 파일의 경우, 파일의 끝까지 탐색하고 역순으로 '\ n'문자를 검사 할 수 있습니까? \ n과 \ r \ n이 있다는 것을 알고 있습니다. 다음 코드를 작성하고 매우 사소한 파일을 테스트했습니다. 당신이 가지고있는 파일들에 대해 이것을 테스트해볼 수 있습니까? 내 솔루션이 길어 보인다는 것을 알고 있지만 처음부터 읽고 전체 파일을 다시 쓰는 것보다 빠르다는 것을 알게 될 것입니다.

public static void Truncate(string file, int lines) 
{ 
    using (FileStream fs = File.Open(file, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) 
    { 
     fs.Position = fs.Length; 

     // \n \r\n (both uses \n for lines) 
     const int BUFFER_SIZE = 2048; 

     // Start at the end until # lines have been encountered, record the position, then truncate the file 
     long currentPosition = fs.Position; 
     int linesProcessed = 0; 

     byte[] buffer = new byte[BUFFER_SIZE]; 
     while (linesProcessed < linesToTruncate && currentPosition > 0) 
     { 
      int bytesRead = FillBuffer(buffer, fs); 

      // We now have a buffer containing the later contents of the file 
      for (int i = bytesRead - 1; i >= 0; i--) 
      { 
       currentPosition--; 
       if (buffer[i] == '\n') 
       { 
        linesProcessed++; 
        if (linesProcessed == linesToTruncate) 
         break; 
       } 
      } 
     } 

     // Truncate the file 
     fs.SetLength(currentPosition); 
    } 
} 

private static int FillBuffer(byte[] buffer, FileStream fs) 
{ 
    if (fs.Position == 0) 
     return 0; 

    int bytesRead = 0; 
    int currentByteOffset = 0; 

    // Calculate how many bytes of the buffer can be filled (remember that we're going in reverse) 
    long expectedBytesToRead = (fs.Position < buffer.Length) ? fs.Position : buffer.Length; 
    fs.Position -= expectedBytesToRead; 

    while (bytesRead < expectedBytesToRead) 
    { 
     bytesRead += fs.Read(buffer, currentByteOffset, buffer.Length - bytesRead); 
     currentByteOffset += bytesRead; 
    } 

    // We have to reset the position again because we moved the reader forward; 
    fs.Position -= bytesRead; 
    return bytesRead; 
} 

만 파일의 끝을 삭제 계획되어 있기 때문에, 그것은 큰 파일과 물론 작은 N.이다 특히, 모든 것을 다시 작성 낭비 것, 하나는 인수를 할 수있는 사람이 원한다면 그 모든 라인을 없애고 처음부터 끝까지가는 것이 더 효율적입니다.

+0

고마워요, 내일 먼저 시도해 볼게요. 꼭 필요한 걸 할 것 같습니다. –

+0

아름답게 일했습니다. 도움을 주신 모든 분들께 감사드립니다. –

3

당신은 실제로 StreamReader를 읽지 않습니다. 사실, 당신이 요구하는 패턴에 대해서는 StreamReader가 전혀 필요하지 않습니다.

IEnumerable<string> allBut = File.ReadLines(path).Reverse().Skip(5).Reverse(); 

이전 결함 버전을 다시 주석 스레드

List<string> allLines = File.ReadLines(path).ToList(); 
IEnumerable<string> allBut = allLines.Take(allLines.Count - 5); 
+0

전체 파일을 읽기 쉬운 대안으로 제안하고 있습니다 (ReadLines.Count는 전체 파일을 읽습니다)? –

+1

네 말이 맞아. 방금 몇 가지 테스트를 통과했습니다. 두 번째 방법은 지속적으로 빠릅니다. 감사. 내 대답을 업데이트하여 첫 번째 옵션을 제거하십시오. – xcud

+0

+1 -'Chr (13)'- 1 바이트를 찾고있는 동안 자신을 역순으로 처리하면 성능이 향상 될 수 있지만, 여전히 대안보다 더 빠를 것입니다. –

3

에 대한 응답으로 당신이 언급되어 있기 때문에 :하는 System.IO.File는 대신 활용할 수있는 유용한 정적 메서드 'readlines도'를 가지고 파일의 줄을 텍스트 파일이라고 가정합니다. 그냥 선을 얻고 싶은 경우에 당신과 같이 문자열의 배열로 읽을 수 있습니다

string[] lines = File.ReadAllLines(@"C:\test.txt"); 

을 또는 당신이 정말로 StreamReaders 작업을해야하는 경우 :

using (StreamReader reader = new StreamReader(@"C:\test.txt")) 
     { 
      while (!reader.EndOfStream) 
      { 
       Console.WriteLine(reader.ReadLine()); 
      } 
     } 
+0

'StreamReader'의 사용은 OP가 텍스트에 대해 이야기하고 있다고 가정 할만큼 충분해야합니다. –

+0

질문을하는 사람이 StreamReader가 필요하다는 것을 알고 있는지 또는 파일을 읽을 필요가 있다는 것을 알았고 빠른 검색을 온라인으로하고 StreamReader가 표시되는 것을 알았는지 확실하지 않았습니다. 하지만 네, 맞습니다. – BryanJ

관련 문제