写文件内存不足c#

时间:2015-08-13 09:52:19

标签: c# out-of-memory streamreader streamwriter

我遇到了一些c#windows窗体的问题 我的目标是将一个大文件(可能> 5GB)切成文件,每个文件包含一百万行 根据下面的代码,我不知道它为什么会内存不足。

感谢。

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();
}

1 个答案:

答案 0 :(得分: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方法每隔x毫秒更新一次控件(因为您在辅助线程上),

例如:

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();

请注意它将如何每100毫秒写一次label5,一开始就写一次(通过设置milliseconds&#34的初始值;及时#34;),每次输出文件已更改(通过设置milliseconds&#34;的值及时#34;)以及处理完所有内容后。

可以使用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]);
}