2015-08-13 2 views
-2

У меня возникают проблемы с формой C# windows.
Моя цель - нарезать большой файл (возможно> 5 ГБ) в файлы, и каждый файл содержит миллион строк.
Согласно приведенному ниже коду, я понятия не имею, почему он будет не в памяти.
записать файл из памяти C#

Спасибо.

StreamReader readfile = new StreamReader(...); 
StreamWriter writefile = new StreamWriter(...);  
string content; 
while ((content = readfile.ReadLine()) != null) 
{ 
    writefile.Write(content + "\r\n"); 
    i++; 
    if (i % 1000000 == 0) 
    { 
     index++; 
     writefile.Close(); 
     writefile.Dispose(); 
     writefile = new StreamWriter(...); 
    } 
    label5.Text = i.ToString(); 
    label5.Update(); 
} 
+3

Файл может иметь очень длинную линию ... Если, например, файл имеет строчный длинную 100mb, то вы могли бы иметь проблемы. – xanatos

+1

xanatos является правильным. Распечатайте длину строки в консоли ('if (длина> 100000) print (length)'). – usr

+0

использовать метод 'Read'. укажите количество символов для чтения: 'char [] ch = new char [100000];' затем заполните его 'readfile.Read (ch, 0, ch.Length);'. наконец, напишите заполненный символ char [] ('ch') в файл –

ответ

1

ошибка, вероятно, в

label5.Text = i.ToString(); 
label5.Update(); 

просто сделать тест я написал что-то вроде:

for (int i = 0; i < int.MaxValue; i++) 
{ 
    label1.Text = i.ToString(); 
    label1.Update(); 
} 

приложение зависает около 16000-18000 (Windows 7 Pro SP1 x64, приложение с x86 и x64).

Возможно, что, запустив длительную операцию в главном потоке приложения, вы остановите очередь сообщений в окне и в какой-то момент замерзаете. Вы можете видеть, что это проблема, добавив

Application.DoEvents(); 

вместо

label5.Update(); 

Но даже это ложное решение. Правильное решение перемещает копирование в другом потоке и обновления управления каждые х миллисекунд, используя метод Invoke (потому что вы на вторичном потоке),

Например:

public void Copy(string source, string dest) 
{ 
    const int updateMilliseconds = 100; 

    int index = 0; 
    int i = 0; 
    StreamWriter writefile = null; 

    try 
    { 
     using (StreamReader readfile = new StreamReader(source)) 
     { 
      writefile = new StreamWriter(dest + index); 

      // Initial value "back in time". Forces initial update 
      int milliseconds = unchecked(Environment.TickCount - updateMilliseconds); 

      string content; 
      while ((content = readfile.ReadLine()) != null) 
      { 
       writefile.Write(content); 
       writefile.Write("\r\n"); // Splitted to remove a string concatenation 
       i++; 

       if (i % 1000000 == 0) 
       { 
        index++; 
        writefile.Dispose(); 
        writefile = new StreamWriter(dest + index); 

        // Force update 
        milliseconds = unchecked(milliseconds - updateMilliseconds); 
       } 

       int milliseconds2 = Environment.TickCount; 

       int diff = unchecked(milliseconds2 - milliseconds); 

       if (diff >= updateMilliseconds) 
       { 
        milliseconds = milliseconds2; 
        Invoke((Action)(() => label5.Text = string.Format("File {0}, line {1}", index, i))); 
       } 
      } 
     } 
    } 
    finally 
    { 
     if (writefile != null) 
     { 
      writefile.Dispose(); 
     } 
    } 

    // Last update 
    Invoke((Action)(() => label5.Text = string.Format("File {0}, line {1} Finished", index, i))); 
} 

и назвать его :

var thread = new Thread(() => Copy(@"C:\Temp\lst.txt", @"C:\Temp\output")); 
thread.Start(); 

Обратите внимание, как он будет писать label5 каждые 100 миллисекунд, плюс один раз в начале (путем установки начального значения milliseconds «назад во времени»), каждый раз, когда выходной файл изменить d (установив значение milliseconds «назад во времени») и после того, как все уложилось.

Еще более правильный пример может быть написан с использованием класса BackgroundWorker, который явно существует для этого сценария. В нем есть событие, ProgressChanged, которое может быть подписано для обновления окна.

Что-то вроде этого:

private void button1_Click(object sender, EventArgs e) 
{ 
    BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    backgroundWorker.WorkerReportsProgress = true; 
    backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged; 
    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; 
    backgroundWorker.DoWork += backgroundWorker_DoWork; 
    backgroundWorker.RunWorkerAsync(new string[] { @"C:\Temp\lst.txt", @"C:\Temp\output" }); 
} 

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    BackgroundWorker worker = sender as BackgroundWorker; 

    string[] arguments = (string[])e.Argument; 
    string source = arguments[0]; 
    string dest = arguments[1]; 

    const int updateMilliseconds = 100; 

    int index = 0; 
    int i = 0; 
    StreamWriter writefile = null; 

    try 
    { 
     using (StreamReader readfile = new StreamReader(source)) 
     { 
      writefile = new StreamWriter(dest + index); 

      // Initial value "back in time". Forces initial update 
      int milliseconds = unchecked(Environment.TickCount - updateMilliseconds); 

      string content; 
      while ((content = readfile.ReadLine()) != null) 
      { 
       writefile.Write(content); 
       writefile.Write("\r\n"); // Splitted to remove a string concatenation 
       i++; 

       if (i % 1000000 == 0) 
       { 
        index++; 
        writefile.Dispose(); 
        writefile = new StreamWriter(dest + index); 

        // Force update 
        milliseconds = unchecked(milliseconds - updateMilliseconds); 
       } 

       int milliseconds2 = Environment.TickCount; 

       int diff = unchecked(milliseconds2 - milliseconds); 

       if (diff >= updateMilliseconds) 
       { 
        milliseconds = milliseconds2; 
        worker.ReportProgress(0, new int[] { index, i }); 
       } 
      } 
     } 
    } 
    finally 
    { 
     if (writefile != null) 
     { 
      writefile.Dispose(); 
     } 
    } 

    // For the RunWorkerCompleted 
    e.Result = new int[] { index, i }; 
} 

void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    int[] state = (int[])e.UserState; 
    label5.Text = string.Format("File {0}, line {1}", state[0], state[1]); 
} 

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    int[] state = (int[])e.Result; 
    label5.Text = string.Format("File {0}, line {1} Finished", state[0], state[1]); 
} 
Смежные вопросы