2017-01-14 8 views
3

텍스트 파일을 처리하고 캐리지 리턴으로 끝나는 지 확인해야합니다.텍스트 파일이 캐리지 리턴으로 끝나는 지 어떻게 알 수 있습니까?

전체 내용을 읽고 내용을 변경 한 다음 원본 파일과 동일한 서식을 유지하면서 대상 파일에 다시 써야합니다. 그리고 여기에 문제가 있습니다 : 원본 파일에 줄 바꿈이 포함되어 있는지 여부를 모르겠습니다.

는 나는 이미 시도했다 :

  • StreamReader.ReadLine() 메소드하지만 종료 캐리지 리턴 및/또는 줄 바꿈을 포함하지 않는 반환되는 문자열.
  • 또한 ReadToEnd() 메서드는 해결책이 될 수 있지만 매우 큰 파일의 경우 성능에 대해 궁금합니다. 해결책은 효율적이어야합니다.
  • 마지막 2 문자를 가져 와서 "\ r \ n"과 같은지 확인하면 해결할 수 있지만 많은 인코딩을 처리해야하며 실제로 가져올 수없는 것처럼 보입니다.

파일의 모든 텍스트를 효율적으로 읽고 뉴 라인에서 끝나는 지 어떻게 결정합니까?

+1

어쨌든 전체 내용을 읽어야하는 경우 왜 ReadToEnd() 사용에 대해 걱정합니까? – PhillipH

+0

ReadToEnd()가 파일의 전체 내용을 반환하기 때문에 @PhillipH. – CodeCaster

+0

".txt 파일 처리"의 의미는 무엇입니까? 한 줄씩 그것을 읽고, 약간의 처리를하고 아마도 마지막에 여분의 빈 줄을 읽는 것일까? – Alexei

답변

4

ReadLine()를 통해 파일을 읽고 나면, 당신은 파일이 끝나기 전에 다시 두 개의 문자로 추구 할 수 있으며 CRLF에 그 문자를 비교 :

string s; 
using (StreamReader sr = new StreamReader(@"C:\Users\Main\Desktop\a.txt", encoding: System.Text.Encoding.UTF8)) 
{ 
    while (!sr.EndOfStream) 
    { 
     s = sr.ReadLine(); 
     //process the line we read... 
    } 

    //if (sr.BaseStream.Length >= 2) { //ensure file is not so small 

    //back 2 bytes from end of file 
    sr.BaseStream.Seek(-2, SeekOrigin.End); 

    int s1 = sr.Read(); //read the char before last 
    int s2 = sr.Read(); //read the last char 
    if (s2 == 10) //if (s1 == 13 && s2 == 10) //if sure its windows format 
    { 
     //file is end with CR-LF or LF ... 
     if (s1 == 13) { } //file is end with CR-LF (Windows EOL format) 
     else { } //file is end with just LF, (UNIX/OSX format) 
    } 

} 
+0

그게 더 낫다. – Steve

+0

하지만 한가지주의 할 점은'ReadLine()'은 개행 문자를 먹는다는 것입니다. OP가's' 변수와 개행 문자를 사용하여 파일을 다시 쓰게 될 때, 아마도 개행 문자를 대체 할 것입니다. – CodeCaster

+0

고마워. 이것은 확실히 작동하지만, UTF-8 인코딩 만 가능합니다. 제 경우와 같이 여러 유형의 인코딩을 처리해야한다면 훨씬 더 많은 작업이 필요하게 될 것입니다. –

2

그래서 당신은 당신이 필요로하는 의미있는 텍스트 파일을 처리하고 모든 텍스트를 읽고, 심지어 파일의 끝에서 개행 문자를 보존하려고합니다.

ReadLine()은 파일이 1로 끝나지 않더라도 올바르게 처리됩니다. 사실 ReadLine()은 파일이 끝에서 두 번째 줄을 읽은 후에 이 true 인 경우 마지막 캐리지 리턴을 사용합니다. ReadAllText() also eats the last newline. 잠재적으로 대용량 파일을 처리 할 때 메모리에서 전체 파일을 한 번에 읽지 않으려 고합니다.

UTF-16과 같이 문자를 인코딩 할 때 둘 이상의 바이트를 사용하는 인코딩이 있기 때문에 파일의 마지막 두 바이트를 비교할 수도 없습니다. 따라서 인코딩을 인식하는 파일을 읽어야합니다. StreamReader는 그 일을합니다. 이 \n에 종료 여부를

public static class StreamReaderExtensions 
{ 
    public static string ReadLineWithNewLine(this StreamReader reader) 
    { 
     var builder = new StringBuilder(); 

     while (!reader.EndOfStream) 
     { 
      int c = reader.Read(); 

      builder.Append((char) c); 
      if (c == 10) 
      { 
       break; 
      } 
     } 

     return builder.ToString(); 
    } 
} 

그런 다음 마지막 반환 라인을 확인할 수 있습니다

그래서 해결책은 마지막에 개행 문자 (들)을 포함 ReadLine()의 자신의 버전을 생성하는 것입니다 : StreamReader가 많이 최적화되어 있지만

string line = ""; 

using (var stream = new StreamReader(@"D:\Temp\NewlineAtEnd.txt")) 
{ 
    while (!stream.EndOfStream) 
    { 
     line = stream.ReadLineWithNewLine(); 
     Console.Write(line); 
    } 
} 

Console.WriteLine(); 

if (line.EndsWith("\n")) 
{ 
    Console.WriteLine("Newline at end of file"); 
} 
else 
{ 
    Console.WriteLine("No newline at end of file"); 
} 

, 나는 한 번에 하나 개의 문자를 읽기의 성능에 대한 신뢰도를 보장 할 수 없습니다. 두 개의 동일한 100MB 텍스트 파일을 사용한 빠른 테스트는 ReadLine() (~ 1800 대 ~ 400ms)에 비해 상당히 급격한 속도 저하를 나타 냈습니다.

이 접근법은 원래 줄 끝을 유지하지만, \n\r\n 또는 그 반대로 모두 변경하지 않고이 확장 메서드에서 반환 한 문자열을 사용하여 안전하게 파일을 다시 쓸 수 있습니다.

+0

파일이 UTF-8 (말)이고 [유니 코드 평면] (https://en.wikipedia.org/wiki/Plane_ (유니 코드)) 0 외부의 문자가 포함되어 있어도 작동합니다.이 경우 파일이 나타납니다 while 루프는 필요에 따라 문자에 대해 UTF-16 코드 단위 (.NET에서'char' 값이라고 함)를 만드는 단일 문자에 대해 두 번 반복합니다 ([surrogate pair] (https : // en .wikipedia.org/wiki/UTF-16 # U.2B10000_to_U.2B10FFFF)). 'Read()'의 리턴 타입이'int' 일 때 잘 문서화되지 않았습니다. UTF-32를 사용하여 한 번에 전체 문자를 반환한다고 생각할 수있었습니다. –

+0

@ 제페 감사합니다. 그리고 저는 텍스트 인코딩과 .NET이 유니 코드를 처리하는 방법에 대해 한두 가지를 알고 있다고 생각했습니다. 따라서 다른 체크를 추가하여'Read()'가 surrogate pair의 전반부를 반환했는지 확인하고, 만약 그렇다면 코드 포인트가 10이더라도 후반부를'\ n'으로 취급하지 않아야합니까? 10은 서로 게이트 쌍의 유효한 후반 절반입니까? 나는 더 많은 테스트를 지금 할 수 없다. – CodeCaster

+1

아니요, 16 비트 코드 단위는 대리 구성 요소와 일반 "단일"코드 포인트 모두로 유효하지 않습니다. 16 비트 코드 단위 (.NET의'char')의 정확한 값에 따라 (1) "단일"코드 포인트 또는 (2) 대리 쌍의 하위 부분이거나 (3) 서로 게이트 쌍 (surrogate pair)의 윗부분 (upper part)이지만 결코 그 세 개 중 하나 이상일 수는 없다. 따라서 잘못된 파일이 발견되지 않는다고 가정하면 실제로 사용하는 것에 대해 걱정할 필요가 없습니다. –