string.split () “Out of exceção de memória” quando o separador de leitura separadas arquivo

StackOverflow https://stackoverflow.com/questions/1404435

  •  05-07-2019
  •  | 
  •  

Pergunta

Eu estou usando string.split () no meu código C # para guia de leitura separadas arquivo. Estou enfrentando "exceção OutOfMemory" como mencionado no exemplo de código.

Aqui eu gostaria de saber por que problema está vindo para arquivo com tamanho de 16 MB?

Esta é a abordagem certa ou não?

using (StreamReader reader = new StreamReader(_path))
{
  //...........Load the first line of the file................
  string headerLine = reader.ReadLine();

  MeterDataIPValueList objMeterDataList = new MeterDataIPValueList();
  string[] seperator = new string[1];   //used to sepreate lines of file

  seperator[0] = "\r\n";
  //.............Load Records of file into string array and remove all empty lines of file.................
  string[] line = reader.ReadToEnd().Split(seperator, StringSplitOptions.RemoveEmptyEntries);
  int noOfLines = line.Count();
  if (noOfLines == 0)
  {
    mFileValidationErrors.Append(ConstMsgStrings.headerOnly + Environment.NewLine);
  }
  //...............If file contains records also with header line..............
  else
  {
    string[] headers = headerLine.Split('\t');
    int noOfColumns = headers.Count();

    //.........Create table structure.............
    objValidateRecordsTable.Columns.Add("SerialNo");
    objValidateRecordsTable.Columns.Add("SurveyDate");
    objValidateRecordsTable.Columns.Add("Interval");
    objValidateRecordsTable.Columns.Add("Status");
    objValidateRecordsTable.Columns.Add("Consumption");

    //........Fill objValidateRecordsTable table by string array contents ............

    int recordNumber;  // used for log
    #region ..............Fill objValidateRecordsTable.....................
    seperator[0] = "\t";
    for (int lineNo = 0; lineNo < noOfLines; lineNo++)
    {
      recordNumber = lineNo + 1;
      **string[] recordFields = line[lineNo].Split(seperator, StringSplitOptions.RemoveEmptyEntries);** // Showing me error when we  split columns
      if (recordFields.Count() == noOfColumns)
      {
        //Do processing
      }
Foi útil?

Solução

Split de execução incorrecta, e ter problema de desempenho sério quando aplicado em grandes cadeias. Por favor, consulte este artigo para obter detalhes sobre os requisitos de memória por função split :

O que acontece quando você faz um split em uma string contendo 1355049 vírgula cordas de 16 caracteres cada separados, tendo comprimento total caráter de 25.745.930?

  1. Um Array de ponteiros para objeto string: espaço de endereço virtual contíguo de 4 (ponteiro endereço) * 1.355.049 = 5.420.196 (tamanho de matrizes) + 16 (para contabilidade) = 5420212.

  2. Não-contíguo espaço de endereço virtual para 1355049 cordas, cada um dos 54 bytes. Isso não significa que todos os 1,3 milhão de cordas seriam espalhados por toda a pilha, mas eles não vão ser alocados em LOH. GC irá alocá-los em cachos sobre Gen0 heap.

  3. Split.Function criará matriz interna de System.Int32 [] de tamanho 25745930, consumindo (102983736 bytes) ~ 98MB de LOH, que é muito caro L.

Outras dicas

Tente não lendo o arquivo inteiro em uma matriz em primeiro lugar "reader.ReadToEnd ()" Leia o arquivo linha por linha directa ..

  using (StreamReader sr = new StreamReader(this._path))
        {
            string line = "";
            while(( line= sr.ReadLine()) != null)
            {
                string[] cells = line.Split(new string[] { "\t" }, StringSplitOptions.None);
                if (cells.Length > 0)
                {

                }
            }
        }

Eu recomendaria linha por linha, se puder ler, mas às vezes dividindo por novas linhas não é o requisito.

Assim, você sempre pode escrever a sua própria memória divisão eficiente. Isso resolveu o problema para mim.

    private static IEnumerable<string> CustomSplit(string newtext, char splitChar)
    {
        var result = new List<string>();
        var sb = new StringBuilder();
        foreach (var c in newtext)
        {
            if (c == splitChar)
            {
                if (sb.Length > 0)
                {
                    result.Add(sb.ToString());
                    sb.Clear();
                }
                continue;
            }
            sb.Append(c);
        }
        if (sb.Length > 0)
        {
            result.Add(sb.ToString());
        }
        return result;
    }

Eu uso o meu próprio. Foi testada com ensaios de 10 unidades ..

public static class StringExtensions
{

    // the string.Split() method from .NET tend to run out of memory on 80 Mb strings. 
    // this has been reported several places online. 
    // This version is fast and memory efficient and return no empty lines. 
    public static List<string> LowMemSplit(this string s, string seperator)
    {
        List<string> list = new List<string>();
        int lastPos = 0;
        int pos = s.IndexOf(seperator);
        while (pos > -1)
        {
            while(pos == lastPos)
            {
                lastPos += seperator.Length;
                pos = s.IndexOf(seperator, lastPos);
                if (pos == -1)
                    return list;
            }

            string tmp = s.Substring(lastPos, pos - lastPos);
            if(tmp.Trim().Length > 0)
                list.Add(tmp);
            lastPos = pos + seperator.Length;
            pos = s.IndexOf(seperator, lastPos);
        }

        if (lastPos < s.Length)
        {
            string tmp = s.Substring(lastPos, s.Length - lastPos);
            if (tmp.Trim().Length > 0)
                list.Add(tmp);
        }

        return list;
    }
}

Tente ler o linewise arquivo em vez de dividir todo o conteúdo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top