Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > StringBuilder и OutOfMemoryException


Автор: m9yt 14.4.2012, 01:05
Привет всем. Делаю небольшой текстовый редактор и натолкнулся на следующую проблему:
при загрузке достаточно большого файла через StringBuilder вылетает OutOfMemoryException, что логично. Но, пытаясь вызвать метод Clear() у объекта StringBuilder, вновь вылетает то же исключение. Что за дела? Не могу очистить память от большого файла.
Код

private void OpenMenuItemClick(object sender, EventArgs e)
{
    openFileDialog.FileName = String.Empty;
    if( openFileDialog.ShowDialog() != DialogResult.OK )
        return;
    filePath = openFileDialog.FileName;
    var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
    var reader = new StreamReader(fileStream, Encoding.Default);
    var buf = new StringBuilder();
    try
    {
        while(!reader.EndOfStream)
        {
            buf.AppendLine(reader.ReadLine());
        }
        textBox.Text = buf.ToString();
        var fileInfo = new FileInfo(filePath);
        Text = string.Format("{0} — TextEditor", fileInfo.Name);
    }
    catch (OutOfMemoryException)
    {
        MessageBox.Show("Недостаточно памяти для загрузки файла!", "Ошибка приложения", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.Message, "Ошибка приложения", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        buf.Clear();// тут - то и вылетает повторно OutOfMemoryException, если я пытался загрузить большой файл
        reader.Close();
        fileStream.Close();
    }
}

Автор: dextermd 14.4.2012, 20:31
Данный метод можно упростить следующим образом:
1) Выкинуть FileStream;
2) Вместо StringBuilder'a использовать метод ReadToEnd() из класса StreamReader;
3) Вместо блока finally обернуть StreamReader в блок using, таким образом после завершения работы StreamReader'a все ресурсы освободятся автоматически;
4) Для определения имени файла использовать статический метод Path.GetFileName().

Код

private void OpenMenuItemClick(object sender, EventArgs e)
{
    openFileDialog.FileName = String.Empty;
    if (openFileDialog.ShowDialog() != DialogResult.OK)
        return;
    filePath = openFileDialog.FileName;

    using (StreamReader reader = new StreamReader(filePath, Encoding.Default))
    {
        try
        {
            textBox.Text = reader.ReadToEnd();
            Text = string.Format("{0} — TextEditor", Path.GetFileName(filePath));
        }
        catch (OutOfMemoryException)
        {
            MessageBox.Show("Недостаточно памяти для загрузки файла!", "Ошибка приложения", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message, "Ошибка приложения", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}


Автор: erm0l0v 17.4.2012, 08:26
Вы не можете разместить в памяти файл произвольного размера. В Notepad например помойму файлы разметом 13+ МБ вообще не загружаются.
Если вы хотите сделать редактор который сможет редактировать любые файлы придется загружать их по блокам. Но тут встает вопрос с освобождением памяти, как C# будет память освобождать это большая загадка. Метод Clear  совсем не обязан освободить память он только закрывает ресурсы.

Автор: jonie 17.4.2012, 20:03
Цитата(erm0l0v @  17.4.2012,  09:26 Найти цитируемый пост)
Если вы хотите сделать редактор который сможет редактировать любые файлы придется загружать их по блокам. Но тут встает вопрос с освобождением памяти, как C# будет память освобождать это большая загадка

гуглить про MemoryMapedFiles попробуйте - оно поможет жить...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)