是否有一种简单的方法可以搜索csv字符串数组,然后在一行中写入某些数据位。目前它搜索csv文件并根据TextBoxes中的两个用户输入提取某些数据,然后对其进行排序并将其写入另一个csv文件。
基本上,如果设备名称相同,我希望它在同一行上写入数据。假设一个设备被称为“dev1 id1”,另一个设备被称为“dev1 id2”。我不想在单独的行上编写(就像现在一样),我希望它能在单个组合行中写入。类似的东西:
dev1,id1,id2
而不是:
dev1,id1
dev1,id2
我尝试过使用for循环和if语句,但很快就会变得混乱。贝娄是我目前的代码(对于因工作原因我必须重新输入的任何拼写错误而感到抱歉。)
StreamWriter sw = new StreamWriter(@"c:\test.csv");
StreamReader sr = new StreamReader(@"c:\rtest.csv");
List<string> list = new List<string>();
string line = "Station,Device,Key,AOR";
string sta = textBox1.Text;
string[] devs = richTextBox1.Text.Split(',').Select(dev => dev.Trim()).ToArray();
string[] sort,strs;
bool cont;
sw.WriteLine(line);
while (!sr.EndOfStream)
{
strs = line.Split(',');
cont = (devs.Any(s => strs[1].IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0));
if (strs[2].ToString() == sta && cont ==true)
{
list.Add(line.ToString());
}
line = sr.ReadLine();
}
sort = new string[list.Count];
list.CopyTo(sort);
Array.Sort(sort);
foreach (string var in sort)
{
strs = var.Split(',');
sw.WriteLine(string.Format("{2},{1},{0},{3}", strs[0], strs[1], strs[2], strs[3]));
}
sw.Close();
if (File.Exists(@"c:\test.csv")
{
Process.Start(@"c:\test.csv");
}
希望我的问题是可以理解的,谢谢。
答案 0 :(得分:1)
您应该使用第三方解析器来读取您的CSV文件 - 这样可以减轻您的负担。
例如,使用KBCsv,您的代码看起来像这样(最初用VB.NET编写,我为任何转换错误道歉):
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
using (CsvReader reader = new CsvReader("Input.csv")) {
foreach (string[] record in reader.DataRecordsAsStrings) {
//assuming each record contains exactly 2 columns, under index 0 and 1
string key = record[0];
string value = record[1];
List<string> targetList = null;
if (!dict.TryGetValue(key, out targetList))
{
targetList = new List<string>();
dict.Add(key, targetList);
}
targetList.Add(value);
}
}
List<string> output = new List<string>();
foreach (KeyValuePair<string, List<string>> kv in dict)
{
string outputCsvLine = kv.Key + "," + string.Join(",", kv.Value);
output.Add(outputCsvLine);
}
System.IO.File.WriteAllLines("output.csv", output);
要编写输出,您可能需要考虑转义CSV特殊字符,例如逗号和引号,如果它们在您的值中。
编辑:如果您真的希望避免使用任何第三方组件(出于安全或其他原因),您可以将上述代码中的第2行和第3行更改为:
using (System.IO.StreamReader reader = new System.IO.StreamReader("Input.csv")) {
foreach (string rawRecord in reader.ReadLine()) {
string[] record = rawRecord.Split(",");
免责声明:使用这样的CSV文件是一种不好的做法,但对于您的特定示例,它可以正常工作。其余的代码保持不变。
答案 1 :(得分:1)
使用逗号简单地拆分CSV行不是一种可靠的方法。字段可以包含逗号,甚至是新行。
正如所指出的,.NET中有一个库可以驱动读取CSV文件。或者您可以使用我在文章Reading and Writing CSV Files in C#中提供的代码。
答案 2 :(得分:1)
使用Linq清理代码。
您需要的只是实现IEnumerable的东西。我已经包含了一个非常基本的版本,分为“,”。
keySelector lambda提取密钥
valueSelector lambda提取值
[TestMethod]
public void CsvParser()
{
string columns = "Device,Id";
string source = "Dev1,id1" + Environment.NewLine + "Dev1,id2" + Environment.NewLine + "Dev2,id3" + Environment.NewLine + "Dev2,id4";
List<string> columnNames = columns.Split(',').ToList();
int keyIndex = columnNames.IndexOf("Device");
int valueIndex = columnNames.IndexOf("Id");
GroupByKey(keyIndex, valueIndex, source);
}
private void GroupByKey(int keyIndex, int valueIndex, string source)
{
LineReader reader = new LineReader(new StringReader(source));
Func<string[], string> keySelector = lineItems => lineItems[keyIndex];
Func<string[], string> valueSelector = lineItems => lineItems[valueIndex];
List<string> idsByDev = reader
// .Skip(1) <-- Uncomment if first row contains headers
.GroupBy(keySelector, valueSelector, StringComparer.OrdinalIgnoreCase)
.Select(device => device.Key + "," + string.Join(",", device))
.ToList()
;
Console.WriteLine( string.Join(Environment.NewLine, idsByDev ));
}
public class LineReader : IEnumerable<string[]>
{
private readonly TextReader source;
public LineReader( TextReader source )
{
this.source = source;
}
public IEnumerator<string[]> GetEnumerator()
{
return new LineReaderEnumerator(this.source);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class LineReaderEnumerator : IEnumerator<string[]>
{
private TextReader source;
public LineReaderEnumerator(TextReader source)
{
this.source = source;
}
public void Dispose()
{
this.source.Dispose();
}
public bool MoveNext()
{
// Replace these lines with a good CSV parser
string line = source.ReadLine();
if (!String.IsNullOrEmpty(line))
{
this.Current = line.Split(',');
}
else
{
this.Current = null;
}
return this.Current != null;
}
public void Reset()
{
throw new NotImplementedException();
}
public string[] Current { get; private set; }
object IEnumerator.Current
{
get { return Current; }
}
}
}