2013-10-14 7 views
1

У меня есть огромный (~ 500K) текстовый файл, который выглядит следующим образом:Извлечение массива из текстового файла

{ // H-20e180a.wav 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,730,4751,3861}, 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,} 
} 

(Примечание: в самом файле есть некоторые дополнительные помехи, и массив-пары намного дольше каждый ~ 140 elts).

Я ищу, чтобы создать C#/.NET рутина, которая позволяет мне извлечь пару массивов:

int [] [] elev_neg20__azi_180 = ArraysForLocation(-20, 180); 

Что бы мою основную стратегию?

С моих дней кодирования BASIC я читал в одной строке за раз, ища «// H», затем извлекал 2 числа, и если они совпадают, я обрабатывал следующие две строки. Но с тех пор ситуация, вероятно, изменилась!

Я предполагаю, что нет ярлыка для чтения через весь файл ...

+0

Я не думаю, что int [] [] - это пара массивов. Как выглядит ваш файл и каков ваш желаемый результат? Вы показали нам метод и не сказали, что он делает. Пожалуйста, будьте более точными. – Tarec

ответ

1

Вы можете использовать метод String.split (Char []): http://msdn.microsoft.com/en-us/library/b873y76a.aspx

Этот метод возвращает массив строк.

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

2

Из моих дней кодирования BASIC, я прочитал в одной строке в то время, ища «// H», затем извлечь 2 числа, и если они совпадают, я бы обрабатывать следующие две строки.

Подходите так же. Используя System.IO.StreamReader вы можете повторно ReadLine, пока не найдете нужный раздел, прочитайте следующие две строки данных и Close. Затем String.Split значения, разделенные запятой, и Convert.ToInt32.

И на самом деле вы, вероятно, прямо не позвонили бы Close. Класс StreamReader реализует IDisposable, поэтому лучше всего обернуть его в оператор using (который автоматически вызывает Dispose, который закроет поток).

using (var reader = new StreamReader("somefile.txt")) 
{ 
    string line = reader.ReadLine(); 
} 

Синтаксический строку, содержащую строку данных можно сделать так:

string line = "{-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,730,4751,3861},"; 

var regex = new Regex("[{},]"); 
int[] ints = regex.Replace(line, " ").Trim(). 
        Split(new char[] { ' ' }).Select(int.Parse).ToArray(); 

Вариант для возвращения массивов из метода заключается в использовании out значения. Таким образом, ваше нормальное возвращаемое значение может использоваться для указания успеха. Способ подписи, как это:

public bool ArraysForLocation(int x, int y, out int[] array1, out int[] array2) 

можно было бы назвать так:

int[] a1; 
int[] a2; 
bool ok = ArraysForLocation(-20, 180, out a1, out a2); 

Я предполагаю, что нет ярлыка для чтения через весь файл ...

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

1

Если вы делаете много поиска и скорость важнее памяти, вы можете захотеть обработать файл один раз и поместить информацию в словарь. Таким образом, поиск выполняется очень быстро, и вам нужно только один раз прочитать файл.

Вот код, который будет анализировать данные, как, например, вы дали:

class Program 
{ 
    static void Main(string[] args) 
    { 
     string filename = "example.txt"; 

     Dictionary<string, int[][]> myDictionary = new Dictionary<string, int[][]>(); 

     BuildMyDataDictionary(filename, myDictionary); 

     //lookup via key 
     int x = 20; 
     int y = 180; 
     string key = string.Format("{0}.{1}", x, y); 
     int[][] values = myDictionary[key]; 

     //print the values to check 
     foreach (int[] array in values) 
      foreach (int i in array) 
       Console.Write(i + ", "); 
     Console.WriteLine(); 

     Console.ReadKey(); 
    } 

    private static void BuildMyDataDictionary(string filename, Dictionary<string, int[][]> myDictionary) 
    { 
     using (StreamReader r = new StreamReader(filename)) 
     { 
      string line = r.ReadLine(); 
      // read through the file line by line and build the dictionary 
      while (line != null) 
      { 
       Regex regx = new Regex(@"//\s*H\-(\d*)\w(\d*)"); 
       Match m = regx.Match(line); 
       if (m.Success) 
       { 
        // make a key of the two parts int 1 and int2 separated by a "." 
        string key = string.Format("{0}.{1}", m.Groups[1], m.Groups[2]); 

        // continue reading the block 
        List<int[]> intList = new List<int[]>(); 
        line = r.ReadLine(); 
        while (!Regex.IsMatch(line, @"^\s*\}")) 
        { 
         Regex regex = new Regex("[{},]"); 
         intList.Add(regex.Replace(line, " ").Trim().Split(new char[] { ' ' }).Select(int.Parse).ToArray()); 
         line = r.ReadLine(); 
        } 
        myDictionary.Add(key, intList.ToArray()); 
       } 
       line = r.ReadLine(); 
      } 
     } 
    } 
} 

Пример файла я тестировал с был:

{ // H-20e180a.wav 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,730,4751,3861}, 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,} 
} 
{ // H-21e181a.wav 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,730,4751,3861}, 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,} 
    {-7,5,-4,-1,-9,2,-5,-1,2,-12,12,-33,34,-48,41,-40,16,20,730,4751,3861}, 
} 

Я позаимствовал ИНТ [] разбор и создание из jltrem выше.

+0

Ваш StreamReader должен находиться в инструкции 'using'. В противном случае вам нужно попробовать/уловить/наконец с помощью Dispose в конце. – jltrem

+0

Да, я согласен с тем, что было бы лучше добавить попытку/улов/наконец У меня был оператор using, выше которого я вырезал за пределами основного с использованием System.IO; –

+0

Я не говорю о [использовании директивы] (http://msdn.microsoft.com/en-us/library/sf0df423.aspx). Вам понадобится [using statement] (http://msdn.microsoft.com/en-us/library/yh598w02.aspx) вокруг вашего StreamReader. Вы не закрываете поток файлов, и даже если вы являетесь исключением, это может привести к тому, что он не будет правильно удален. Использующий блок обрабатывает это для вас. 'using (var r = new StreamReader (filename)) {...}' - это то, что вам нужно добавить. (это было объяснено в моем ответе) – jltrem

Смежные вопросы