2013-11-26 7 views
0

각 파일의 첫 번째 항목 인 키를 기준으로 큰 파일 (큰 따옴표로 묶은 각 용어)을 많은 작은 파일로 분할하려고합니다. 일반적으로 동일한 키를 사용하는 하나 이상의 레코드입니다.하나의 파일을 여러 개의 작은 파일로 분할하기위한 최적화

이 큰 파일의 범위는 1GB에서 2GB까지이며, 생성되는 파일의 수는 키의 이름을 따서 명명 된 하위 폴더에 각각 10,000-30,000입니다.

C#에서는 각 행에서 StreamReader.ReadLine()을 수행하고 결과가 다른 키 (이전 키의 마지막 데이터를 알리는 신호)에 도달 할 때까지 연결 한 다음 파일을 쓰는 함수를 호출합니다 비 동시성으로. Windows에서 이러한 파일을 정렬하여 일련의 키를 만들도록 요청하고 있습니다. 따라서 한 번 파일을 열어야 만합니다. 그러나 작업을 완료하는 데 20 분 정도 걸립니다. 이 속도를 높이는 방법이 있습니까? 애프터 (

sfd = new SaveFileDataDelegate(this.SaveFileData); 



private void CSVParse(string filename, string unzippedFilePath, string feedname) 
{ 
    StreamReader filestream = null; 
    FileStream readerStream = null; 
    try 
    { 
     readerStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, 120000, FileOptions.SequentialScan); 
     filestream = new StreamReader(readerStream, Encoding.UTF8, false, 120000); 

     string tempstring = ""; 
     string buffer = ""; 
     string lastlotkey = ""; 
     IAsyncResult result = null; 

     activityLog.Log("Parsing File: " + filename); 

     while (((tempstring = filestream.ReadLine()) != null) || buffer != "") 
     { 
      if (tempstring == null) 
      { 
       tempstring = ""; 
      } 
      string lotkey = tempstring.Replace("\"","").Split(',').First(); 
      if (lotkey == tempstring && tempstring != "") 
      { 
       break; 
      } 
      if (lotkey == "DealerID") 
      { 
       continue; 
      } 
      if (lastlotkey == "") 
      { 
       lastlotkey = lotkey; 
      } 
      if ((lotkey != lastlotkey && buffer.Length > 0)) 
      { 
       result = sfd.BeginInvoke(outputDirectory + @"\" + feedname + @"\" + lastlotkey + @"\" + (filename.Split('\\').Last()).Split('.').First() + ".txt", buffer, outputDirectory + @"\" + feedname + @"\" + lastlotkey,null,null); 
       lastlotkey = lotkey; 
       buffer = ""; 

       if (tempstring == "") 
       { 
        continue; 
       } 
      } 
      if (buffer.Length > 0) 
      { 
       buffer = buffer + "\r\n"; 
      } 
      buffer = buffer + tempstring; 
     } 
     filestream.Close(); 
     readerStream.Close(); 
     if (result != null) 
     { 
      result.AsyncWaitHandle.WaitOne(-1); 
     } 
     return; 
    } 

    catch (Exception e) 
    { 
     activityLog.Log("Error Occurred: " + e.ToString()); 
     if (filestream != null) 
     { 
      filestream.Close(); 
     } 
     hadError = true; 
     return; 
    } 
} 


private void SaveFileData(string file, string buffer, string directory) 
{ 
    // create file from last lot key with data from parsing, write, close, update lastlotkey 
    Directory.CreateDirectory(directory); 
    FileStream fs = null; 
    StreamWriter temp = null; 
    try 
    { 
     if (!File.Exists(file)) 
     { 
      fs = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 120000); 
     } 
     else 
     { 
      fs = new FileStream(file, FileMode.Truncate, FileAccess.Write, FileShare.None, 120000); 
     } 
     temp = new StreamWriter(fs, Encoding.UTF8, 120000); 
     temp.AutoFlush = false; 
     temp.WriteLine(headerLine); 
     temp.Write(buffer); 
     temp.Flush(); 
     temp.Close(); 
     fs.Close(); 
    } 
    catch (Exception e) 
    { 
     activityLog.Log("Error Occurred: " + e.ToString()); 
     if (fs != null) 
     { 
      fs.Close(); 
     } 
     if (temp != null) 
     { 
      temp.Close(); 
     } 
     hadError = true; 
     return; 
    } 
} 

편집

나는 스택 오버플로와 인터넷의 깊은 창자 크롤링 및 라인으로 라인을 프로파일 링 후에 나는 문자열 연결 실제로 파싱 루틴의 무거운 것을 발견 파일 복사 및 윈도우 정렬), Stringbuilder로 바꾸면 총 처리 시간이 20 분 (복사 + 정렬 + 구문 분석)에서 5 분의 복사 + 정렬 및 2 분의 구문 분석, 총 7 분으로 대폭 늘어났습니다. 속도 향상 130 %

+0

StringBuilder가 다시 나타납니다. 부적절하게 String으로 작성된 프로그램을 디버깅하는 데 낭비되는 시간 낭비가 String internation에 의해 세계에 저장된 총 메모리를 초과했는지 의문입니다. –

답변

0

하드 드라이브에 쓰는 코드를 제거하면 속도는 얼마나 빠릅니까? 하드 드라이브 때문에 많은 속도 저하가 발생합니다. ssd를 얻으십시오 : P

많은 루핑 작업이 있으므로 루프 안의 코드가 제한됩니다. 중복 된 코드를 제거하고 루프 외부에서 최대한 많은 코드를 확보하십시오.

첫 번째가 필요하지 않은 경우 이미 잠시 동안 null을 확인하고 있습니다.

비슷한 줄이 많으면 항상 분할하지 않아도됩니다. 대신에 .Starts를 사용할 수 있습니다.

파일이 일관되면 "~와 비교할 수 있습니다"를 삭제하지 않아도됩니다.

두 번째 if에서 빈 tempstring을 확인합니다. 빈 문자열을 나눌 필요가 없으므로 분할 전에이 작업을 수행하려고 할 수 있습니다.

새 파일 이름을 얻으려면 많은 문자열 조작을 루프 밖에서 수행 할 수 있습니다.

+0

이것은 약간 도움이되는 것 같았습니다. 내 처리 시간은 약 5 % 향상되는 것처럼 보였습니다. 여전히 내 병목 현상이 디스크 IO와 관련되어 있다는 의심이 들었습니다. 파일 열기, 쓰기, 버퍼 크기 등에 대한 제안 사항이 있습니까? – WestonM

+0

@WestonM IO를 더 빠르게 만드는 유일한 방법은 읽기/쓰기 횟수를 제한하고 바늘의 움직임을 제한하는 것입니다 (예 : 많은 파일을 읽고 쓰는 것은 바늘을 쓰기 또는 읽기보다 더 많이 움직일 것입니다 파일). 또는 더 빠른 하드웨어로 업그레이드하십시오. –