我有2个csv文件,file1.csv和file2.csv。每个文件中的某些行将是相同的。我希望创建一个基于file2.csv的第三个csv文件,但是从file1.csv中删除了任何行。实际上我希望从file2.csv中减去file1.csv,忽略file1中不存在于file2中的任何行。 我知道我可以使用streamreader来读取file2.csv中的每一行并在file1.csv中搜索它。如果file1.csv中不存在,我可以将其写入file3.csv。但是,文件非常大(超过30000行),我相信这将需要大量的处理时间。 我怀疑可能有更好的方法将每个csv加载到数组,然后对它们执行简单的减法函数以获得所需的结果。我要感谢对代码或方法的一些帮助,我应该解决这个问题。
文件的示例内容:
file1.csv
dt97861.jpg,149954,c1714ee1,\folder1\folderA\,
dt97862.jpg,149955,c1714ee0,\folder1\folderA\,
dt97863.jpg,59368,cd23f223,\folder2\folderA\,
dt97864.jpg,57881,0835be4a,\folder2\folderB\,
dt97865.jpg,57882,0835be4b,\folder2\folderB\,
file2.csv
dt97862.jpg,149955,c1714ee0,\folder1\folderA\,
dt97863.jpg,59368,cd23f223,\folder2\folderA\,
dt97864.jpg,57881,0835be4a,\folder2\folderB\,
dt97865.jpg,57882,0835be4b,\folder2\folderB\,
dt97866.jpg,57883,0835be4c,\folder2\folderB\,
dt97867.jpg,57884,0835be4d,\folder3\folderA\,
dt97868.jpg,57885,0835be4e,\folder3\folderA\,
我要求的结果是:
file3.csv
dt97866.jpg,57883,0835be4c,\folder2\folderB\,
dt97867.jpg,57884,0835be4d,\folder3\folderA\,
dt97868.jpg,57885,0835be4e,\folder3\folderA\,
编辑: 在下面的帮助下,我找到了以下解决方案,我相信它很优雅:
public static IEnumerable<string> ReadFile(string path)
{
string line;
using (var reader = File.OpenText(path))
while ((line = reader.ReadLine()) != null)
yield return line;
}
然后:
var file2 = ReadFile(file2FilePath);
var file1 = ReadFile(file1FilePath);
var file3 = file2.Except(file1);
File.WriteAllLines(file3FilePath, file3);
答案 0 :(得分:1)
虽然这可能不是最佳方法,但它是我过去使用的方法。这有点肮脏,但是......
* [实际处理代码后编辑的步骤]
根据Bit的请求,我添加了一个使用来自Some Random Website的示例数据的示例 - 这是针对.NET 3.5在VS2008中编写的,但它应该在3.5+上运行。我将us-500复制到2个版本中,原始版本和修改后的1行创建了一个独特的测试值。该项目的目标是x86平台。我使用了新的Windows窗体进行测试
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace TestSandbox
{
public partial class Form1 : Form
{
public Form1()
{
var file1 = new DataTable();
var file2 = new DataTable();
InitializeComponent();
//Gets data from csv file, select allows for filtering
using (var conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\;Extended Properties=""text;HDR=Yes;FMT=Delimited"";"))
{
conn.Open();
using (var adapter = new OleDbDataAdapter(@"select * from [us-500.csv]", conn))
{
adapter.Fill(file1);
}
}
using (var conn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\;Extended Properties=""text;HDR=Yes;FMT=Delimited"";"))
{
conn.Open();
using (var adapter = new OleDbDataAdapter(@"select * from [us-500-2.csv]", conn))
{
adapter.Fill(file2);
}
}
//Moves datatable information to lists for comparison
var file1List = (from DataRow row in file1.Rows select row.ItemArray.Select(field => field.ToString()).ToArray() into fields select string.Join(",", fields)).ToList();
var file2List = (from DataRow row in file2.Rows select row.ItemArray.Select(field => field.ToString()).ToArray() into fields select string.Join(",", fields)).ToList();
//Adds all data from file2 into file1 list, except for data that already exists in file1
file1List.AddRange(file2List.Except(file1List));
//Exports all results to c:\results.csv
File.WriteAllLines(@"C:\Results.csv", file1List.ToArray());
}
}
}
*注意:在查看代码之后,直接导入列表看起来会更有效率,但我现在不会这样做,因为它不会过于复杂。
答案 1 :(得分:1)
假设该行完全相同,您可以将这两个文件读入两个IEnumerable<string>
并使用IEnumerable.Except<T>
进行提取。无论顺序如何,这都会产生相同的结果〜
示例:
var file1 = new List<string>{
@"dt97861.jpg,149954,c1714ee1,\folder1\folderA\,",
@"dt97862.jpg,149955,c1714ee0,\folder1\folderA\,",
@"dt97863.jpg,59368,cd23f223,\folder2\folderA\,",
@"dt97864.jpg,57881,0835be4a,\folder2\folderB\,",
@"dt97865.jpg,57882,0835be4b,\folder2\folderB\,",
};
var file2 = new List<string>{
@"dt97862.jpg,149955,c1714ee0,\folder1\folderA\,",
@"dt97863.jpg,59368,cd23f223,\folder2\folderA\,",
@"dt97864.jpg,57881,0835be4a,\folder2\folderB\,",
@"dt97865.jpg,57882,0835be4b,\folder2\folderB\,",
@"dt97866.jpg,57883,0835be4c,\folder2\folderB\,",
@"dt97867.jpg,57884,0835be4d,\folder3\folderA\,",
@"dt97868.jpg,57885,0835be4e,\folder3\folderA\,",
};
file2.Except(file1).Dump();
输出:
dt97866.jpg,57883,0835be4c,\folder2\folderB\,
dt97867.jpg,57884,0835be4d,\folder3\folderA\,
dt97868.jpg,57885,0835be4e,\folder3\folderA\,
以下是将任何文件加载到IEnumerable<string>
的功能。别忘了using System.IO;
。
public static IEnumerable<string> ReadFile(string path)
{
string line;
using(var reader = File.OpenText(path))
while((line = reader.ReadLine()) != null)
yield return line;
}
将结果写入文件:
//using System.IO; is required
File.WriteAllLines("file3.csv", file2.Except(file1))
备注:File.WriteAllLines
将创建或覆盖该文件。
答案 2 :(得分:0)
步骤1.使用System.IO,我们将使用FileStream读取两个文件,并使用StreamWriter创建第三个文件。
步骤2.使用FileStream读取文件#1。例如
using (var FS = new System.IO.FileStream(file1, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { ...<insert next steps in here>...}
步骤3.嵌套另一个FileStream以读取文件#2。此流将被多次读取,因此如果您可以将较小的文件放在嵌套的这一部分中,那么它是最好的。您可以通过在跳转到这些循环之前检查文件的大小来执行此操作。
步骤4.从我们最大的文件File#1中读取一行,然后我们将它与File#2中的所有行进行顺序比较。如果找到匹配项,则将布尔值设置为TRUE,表示在文件#2中找到匹配的行。
步骤5.一旦我们在文件#2的末尾,检查布尔值的真/假条件。如果为false,请将我们从文件#1读取的字符串保存到文件#3中。这是你的输出文件。
步骤6.将文件#2的流指针重置到文件的开头,例如FS.Seek(0,System.IO.SeekOrigin.Begin)
步骤7.从步骤4开始重复,直到我们到达文件#1的末尾。文件#3的内容应仅代表文件#1中不属于文件#2的唯一条目