2012-09-06 5 views
0

OK, C# winform 앱을 만들었습니다. File_Splitter_Joiner입니다. 파일을 지정하면 지정한 개수만큼 파일이 분할됩니다. 분할은 별도의 스레드에서 수행됩니다. 1Gig 파일을 조각 낼 때까지 모든 것이 잘 작동했습니다! 작업 관리자에서 내 프로그램이 1 기가 바이트의 메모리를 사용하기 시작했고 컴퓨터가 거의 죽는 것을 보았습니다! 단지 썰기가 끝나면 소비가 바뀌지 않았습니다! (가비지 수집기가 작동하지 않는다는 것을 의미하는 경우 dunno, 큰 데이터 덩어리를 보유하고있는 것에 대한 모든 참조를 잃어 버렸으므로 작동해야 함) 여기 Splitter 생성자가 있습니다. 더 나은 아이디어) : 여기메모리 관리 및 프로그램 성능 관련 문제

public FileSplitter(string FileToSplitPath, string PiecesFolder, int NumberOfPieces, int PieceSize, SplittingMethod Method) 
{ 
    FileToSplitInfo = new FileInfo(FileToSplitPath); 
    this.FileToSplitPath = FileToSplitPath; 
    this.PiecesFolder = PiecesFolder; 
    this.NumberOfPieces = NumberOfPieces; 
    this.PieceSize = PieceSize; 
    this.Method = Method; 
    SplitterThread = new Thread(Split); 
} 

그리고 실제 분할했던 방법입니다 : (나는, 아직 안돼서 그래서 당신은 최선의 방법으로 수행 할 '수 없습니다'볼에 대한하는지 지금까지 수, 난 그냥 지금

private void Split() 
{ 
    int remainingSize = 0; 
    int remainingPos = -1; 
    bool isNumberOfPiecesEqualInSize = true; 
    int fileSize = (int)FileToSplitInfo.Length; // FileToSplitInfo is a FileInfo object 
    if (fileSize % PieceSize != 0) 
    { 
    remainingSize = fileSize % PieceSize; 
    remainingPos = fileSize - remainingSize; 
    isNumberOfPiecesEqualInSize = false; 
    } 
    byte[] fileBytes = new byte[fileSize]; 
    var _fs = File.Open(FileToSplitPath, FileMode.Open); 
    BinaryReader br = new BinaryReader(_fs); 
    br.Read(fileBytes, 0, fileSize); 
    br.Close(); 
    _fs.Close(); 

    for (int i = 0, index = 0; i < NumberOfPieces; i++, index += PieceSize) 
    { 
    var fs = File.Create(PiecesFolder + "\\" + Path.GetFileName(FileToSplitPath) + "." + (i+1).ToString()); 
    var bw = new BinaryWriter(fs); 
    bw.Write(fileBytes, index, PieceSize); 
    if(i == NumberOfPieces-1 && !isNumberOfPiecesEqualInSize && Method == SplittingMethod.NumberOfPieces) 
    bw.Write(fileBytes, remainingPos, remainingSize); 
    bw.Close(); 
    fs.Close(); 
    } 
MessageBox.Show("File has been splitted successfully!"); 
SplitterThread.Abort(); 
} 

) 여기 학습, 대신 Binar를 통해 파일의 바이트를 읽고 있어요 yReader, 처음에는 File.ReadAllBytes 메서드를 통해 읽었습니다. 작은 파일 크기에서는 정상적으로 작동했지만, "SystemOutOfMemory" 예외가 발생했을 때 우리는 큰 사람을 처리했을 때 그 예외를 얻지 못했습니다. BinaryReader를 통해 바이트를 읽습니다.

그래서, 주요 질문은, 어떻게 그렇게 많은 메모리를 소비하지 않는 방식으로 큰 파일 (말하기 연주회를)로드 할 수 있습니다 (즉, 질문 사이에 있었다)? 내 프로그램이 그 모든 기억을 소비하지 못하게하려면 어떻게해야합니까? 분할이 완료된 후 사용한 메모리를 해제하려면 어떻게해야합니까? (I 실제로는 동일

bw.Close(); fs.Close(); 

bw.Dispose; fs.Dispose; 

대신 사용. 우리가 뭔가를로드 할 때, 그것은 다른 곳에서 우리의 기억에없는 도착 사촌 나는 질문이 이해가되지 않을 수도 있습니다 알고 ,하지만 내가 그런 질문을 한 이유는, 똑같은 문제가 있었다면, 파일을로드했고, 프로그램은 5Mig 정도의 램을 소비했다는 것을 알기 위해 또 다른 Splitting_Joining 프로그램을 사용했다는 것입니다. 분할 시작, 그것은 약 10Migs를 사용했습니다! 지금 그것은 매우 큰 차이입니다 .. 아마도 그 응용 프로그램은 C/C++ ..

그래서 요약하면, 누가 짜증? 내 코드인가? 그렇다면 어떻게 해결할 수 있습니까? 또는 성능면에서 C#입니까?

당신이 저를 연결 할 수 아무것도 당신에게 SOOO 감사드립니다 :)

+0

아무것도 질문과 관련,하지만 분할의 과거 분사 분할, 분할 할 수 없습니다. :) –

답변

1

할 수있는 다른 측면이 있습니다 더 나은 :

  • 당신은 왜 첫번째 읽기 큰 파일로 작업하는 경우 모두은 배열 안에 있고 후에 다른 파일에 씁니 까? 다른 파일에서 읽는 동안 새 파일에 쓰기 만하면됩니다.

  • using을 사용하면 어떤 경우에도 스트림 예외를 처리 할 수 ​​있습니다.

  • 너가 1GB 또는 더 많은 것 같이 진짜로 큰 파일을 사용하는 것을 시작하면, 나는 Memory Mapped Files을보기 위하여 추천 할 것이다. 따라서 성능 향상과 함께 놀라운 메모리 절약 효과를 누릴 수 있습니다.

2

다음 2 줄 당신을 KIL합니다 : 크기가 Int32.MaxValue 위에있을 때

int fileSize = (int)FileToSplitInfo.Length; // a FileInfo object 
... 
byte[] fileBytes = new byte[fileSize]; 
  1. 귀하의 코드가 실패합니다. 불필요한, 그냥 사용 long fileSize = FileToSplitInfo.Length;
  2. 연속적인 메모리가 충분하지 않으면이 수정 된 코드가 실패합니다. 조각 모음 (LOH의)은 당신을 조만간 무너 뜨릴 것입니다.
  3. 전체 파일에 대해 메모리를 할당하지만 한 번에 PieceSize 바이트 만 필요합니다. 당신은 심지어 이는 파일 크기를 알 필요가 없습니다

, 단지

byte[] pieceBuffer = new byte[PieceSize]; 

while (true) 
{ 
    int nBytes = br.Read(pieceBuffer, 0, pieceBuffer.Length); 
    if (nBytes == 0) 
     break; 

    // write this piece, the length is nBytes 
}