我有一个巨大的(~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 :(得分:2)
从我编写BASIC的日子开始,我会一次读一行,寻找'// H',然后提取2个数字,如果匹配,我会处理接下来的两行。< / em>的
以同样的方式接近它。使用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 :(得分:1)
您可以使用string.Split(Char [])方法:http://msdn.microsoft.com/en-us/library/b873y76a.aspx
此方法返回一个字符串数组。
char参数是您要拆分的分隔符。因此,您可以将其调用一次,将长字符串拆分为所需的两个数组,然后在逗号上拆分每个数组以获取各个值的相应数组。之后,如果需要,您可以将字符串转换为int。
答案 2 :(得分: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借用了int []解析和创建。