#c# #.net #linq #csv
#c# #.net #linq #csv
Вопрос:
У меня есть два файла CSV. В первом файле у меня есть список пользователей, а во втором файле у меня есть список повторяющихся пользователей. Я пытаюсь удалить строки из первого файла, которые равны второму файлу.
Вот код, который у меня есть до сих пор:
StreamWriter sw = new StreamWriter(path3);
StreamReader sr = new StreamReader(path2);
string[] lines = File.ReadAllLines(path);
foreach (string line in lines)
{
string user = sr.ReadLine();
if (line != user)
{
sw.WriteLine(line);
}
Пример файла 1:
Modify,ABAMA3C,Allpay - Free State - HO,09072701
Modify,ABCG327,Processing Centre,09085980
Пример файла 2:
Modify,ABAA323,Group HR Credit Risk amp; Finance
Modify,ABAB959,Channel Sales amp; Service,09071036
Есть предложения?
Спасибо.
Комментарии:
1. Пожалуйста, укажите пример формата файла в вашем сообщении…
2. Ваш код выглядит неполным, вам нужно закрыть цикл foreach и закрыть StreamWriter / Reader
3. Похоже, тоже домашнее задание. Помечено как so, не стесняйтесь изменять, если вы возражаете против этого.
4. Почему бы вам не разделить оба файла CSV на список<String>, где каждый элемент представляет собой строку из вашего файла csv, а затем выполнить предварительный поиск в первом списке csv и проверить, содержится ли строка во втором списке? Что-то вроде: foreach(элемент строки в списке){ if(ListTwo.Contains(элемент)){ //удалить строку из списка здесь}} В конце просто перезапишите свой файл оставшимися результатами.
5. где дублирование, вы имеете в виду дублирование на токен или на строку?
Ответ №1:
Все, что вам нужно сделать, это изменить следующие пути к файлам в приведенном ниже коде, и вы получите файл обратно (file one) без дубликатов пользователей из файла 2. Этот код был написан с учетом идеи, что вам нужно что-то, что легко понять. Конечно, есть другие, более элегантные решения, но я хотел сделать это как можно более простым для вас:
(Вставьте это в основной метод вашей программы)
string line;
StreamReader sr = new StreamReader(@"C:UsersJDesktoptextsFirst.txt");
StreamReader sr2 = new StreamReader(@"C:UsersJDesktoptextsSecond.txt");
List<String> fileOne = new List<string>();
List<String> fileTwo = new List<string>();
while (sr.Peek() >= 0)
{
line = sr.ReadLine();
if(line != "")
{
fileOne.Add(line);
}
}
sr.Close();
while (sr2.Peek() >= 0)
{
line = sr2.ReadLine();
if (line != "")
{
fileTwo.Add(line);
}
}
sr2.Close();
var t = fileOne.Except(fileTwo);
StreamWriter sw = new StreamWriter(@"C:UsersjustinDesktoptextsFirst.txt");
foreach(var z in t)
{
sw.WriteLine(z);
}
sw.Flush();
Ответ №2:
Если это не домашнее задание, а производственная задача, и вы можете устанавливать сборки, вы сэкономите 3 часа своей жизни, если проглотите свою гордость и воспользуетесь частью библиотеки VB:
Существует множество исключений (CR / LF между запятыми = допустимо в кавычках; различные типы кавычек; и т.д.) Это будет обрабатывать все, что Excel будет экспортировать / импортировать.
Пример кода для загрузки класса ‘Person’, извлеченного из программы, в которой я его использовал:
Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser(CSVPath)
Reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
Reader.Delimiters = New String() {","}
Reader.TrimWhiteSpace = True
Reader.HasFieldsEnclosedInQuotes = True
While Not Reader.EndOfData
Try
Dim st2 As New List(Of String)
st2.addrange(Reader.ReadFields())
If iCount > 0 Then ' ignore first row = field names
Dim p As New Person
p.CSVLine = st2
p.FirstName = st2(1).Trim
If st2.Count > 2 Then
p.MiddleName = st2(2).Trim
Else
p.MiddleName = ""
End If
p.LastNameSuffix = st2(0).Trim
If st2.Count >= 5 Then
p.TestCase = st2(5).Trim
End If
If st2(3) > "" Then
p.AccountNumbersFromCase.Add(st2(3))
End If
While p.CSVLine.Count < 15
p.CSVLine.Add("")
End While
cases.Add(p)
End If
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " amp; ex.Message amp; " is not valid and will be skipped.")
End Try
iCount = 1
End While
End Using
Ответ №3:
это для правильного закрытия потоков:
using(var sw = new StreamWriter(path3))
using(var sr = new StreamReader(path2))
{
string[] lines = File.ReadAllLines(path);
foreach (string line in lines)
{
string user = sr.ReadLine();
if (line != user)
{
sw.WriteLine(line);
}
}
}
для получения справки о реальной логике удаления или сравнения, ответьте на комментарий El Ronnoco выше…
Ответ №4:
Вам нужно закрыть потоки или использовать предложение using
sw.Close();
using(StreamWriter sw = new StreamWriter(@"c:test3.txt"))
Ответ №5:
Вы можете использовать LINQ…
class Program
{
static void Main(string[] args)
{
var fullList = "TextFile1.txt".ReadAsLines();
var removeThese = "TextFile2.txt".ReadAsLines();
//Change this line if you need to change the filter results.
//Note: this assume you are wanting to remove results from the first
// list when the entire record matches. If you want to match on
// only part of the list you will need to split/parse the records
// and then filter your results.
var cleanedList = fullList.Except(removeThese);
cleanedList.WriteAsLinesTo("result.txt");
}
}
public static class Tools
{
public static IEnumerable<string> ReadAsLines(this string filename)
{
using (var reader = new StreamReader(filename))
while (!reader.EndOfStream)
yield return reader.ReadLine();
}
public static void WriteAsLinesTo(this IEnumerable<string> lines, string filename)
{
using (var writer = new StreamWriter(filename) { AutoFlush = true, })
foreach (var line in lines)
writer.WriteLine(line);
}
}
Ответ №6:
using(var sw = new StreamWriter(path3))
using(var sr = new StreamReader(path))
{
string []arrRemove = File.ReadAllLines(path2);
HashSet<string> listRemove = new HashSet<string>(arrRemove.Count);
foreach(string s in arrRemove)
{
string []sa = s.Split(',');
if( sa.Count < 2 ) continue;
listRemove.Add(sa[1].toUpperCase());
}
string line = sr.ReadLine();
while( line != null )
{
string []sa = line.Split(',');
if( sa.Count < 2 )
sw.WriteLine(line);
else if( !listRemove.contains(sa[1].toUpperCase()) )
sw.WriteLine(line);
line = sr.ReadLine();
}
}