文件检查和打印
本文关键字:打印 检查和 文件 | 更新日期: 2023-09-27 18:08:49
我正在编写一个程序,该程序每次打开一个文件,对其进行解析,并将解析后的数据输出到一个新的.txt文档中,该文档以传入的文件命名。要读取和解析的文件超过50个。
因此,如果打开的文件命名为:STACK-OVERFLOW-125663-D2.txt
,则输出的文件将命名为125663-D2.txt
。
每次读取文件时,都会解析其零件号。每个文件将包含类似于的行(第8个逗号分隔值(即119082、119083、119040、119085、119084)是部件号值。):
"00003",6,"D","C20",-70.10,42.06,90.00,"119082",0,1,2,0,0,"",0,"001"
"00004",6,"D","C21",-67.91,42.06,90.00,"119082",0,1,2,0,0,"",0,"001"
"00005",13,"D","C23",-66.91,59.07,180.00,"119083",0,1,2,0,0,"",0,"002"
"00006",13,"D","R10",-77.32,66.88,90.00,"119040",0,1,2,0,0,"",0,"003"
"00007",13,"D","L3",-77.64,77.48,90.00,"119085",0,1,2,0,0,"",0,"004"
"00008",20,"D","D1",-62.91,103.77,0.00,"119084",0,1,2,0,0,"",0,"005"
"00009",21,"D","D1",-25.83,103.77,0.00,"119084",0,1,2,0,0,"",0,"005"
"00010",14,"D","L3",-40.56,77.48,90.00,"119085",0,1,2,0,0,"",0,"004"
"00011",14,"D","R10",-40.24,66.88,90.00,"119040",0,1,2,0,0,"",0,"003"
现在我需要做的是检查另一个。txt文件…假设它被称为"DATABASE.txt",看看这些部件号是否已经存在。这个数据库文件看起来像这样:
119082: 125663-D2, 123456-A1,
119083: 125663-D2,
119085: 125663-D2, 123456-A1, 987654321-Z11234, 1111111-B50
所以,在DATABASE.txt文件和上面打开的文件中,我想检查打开的文件中的所有零件号,看看它们是否存在于数据库中。
如果部件确实存在,我想将文件名(输出文件)连接到部件号所在行的末尾。
如果部件不存在,我想将部件添加到文件中,并使用
list.Sort()
对文件进行排序。
我不确定如何做到这一点,有人可以帮助吗?
下面是目前为止我的一些代码:
List<string> partNumberLines = new List<string>();
string file = openFile.FileName;
string splitFile = file.Split('''');
string[] savedName = splitFile[splitFile.Length - 1].Split('.');
string[] lineNumber = savedNamed[2].Split('-');
string fileName = savedNamed[1] + "-" + lineNumber[0] + ".txt";
foreach (string line in fileList)
{
string[] splitLine = line.Split(''n');
for (int i = 0; i < splitLine.Length; i++)
{
string tempSplit = splitLine[i].Split(','); // splits each line by commas
if (tempSplit.Length.Equals(16))
{
tempSplit[7] = tempSplit[7].TrimStart('"'); //trims the quotes from the part numbers
tempSplit[7] = tempSplit[7].TrimEnd('"');
}
}
}
partNumberLines = partNumberLines.Distinct().ToList(); //gets rid of duplicate partnumbers in one file.
所以我的代码得到所有的零件号和文件的名称。我只是不知道如何打开现有的文件(如果它不存在,创建它)并通过文件搜索并在列表中查找匹配: partNumberLines
。如果匹配,将文件名连接到当前行。如果不匹配,则创建新行并添加零件号和文件名,然后按零件号对文件进行数字排序。
希望你没有放弃。下面是一个示例类。我已经完成了我的上一篇文章。将上面的数据库数据保存到database.txt
,将部件数据保存到parts.txt
,并修改路径以查看其工作原理。希望对你有所帮助。如果还有问题,请提出来。
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
private class DataBaseRecord
{
public string PartNumber { get; set; }
public List<string> FileNames { get; set; }
public DataBaseRecord(string _PartNumber, List<string> _FileNames)
{
PartNumber = _PartNumber;
FileNames = _FileNames;
}
}
private class DataBase
{
public string databaseFile { get; set; }
List<DataBaseRecord> records;
public DataBase(string _databaseFile)
{
databaseFile = _databaseFile;
records = new List<DataBaseRecord>();
}
public void AddRecord(string partNumber, string fileName)
{
if (string.IsNullOrWhiteSpace(partNumber))
return;
if (string.IsNullOrWhiteSpace(fileName))
return;
bool exists = records.Count(x => x.PartNumber == partNumber) > 0;
if (!exists)
{
records.Add(new DataBaseRecord(partNumber, new List<string>() { fileName }));
}
else
{
var record = from x in records where x.PartNumber == partNumber select x;
foreach (DataBaseRecord dbr in record)
{
exists = dbr.FileNames.Count(x => x == fileName) > 0;
if (!exists)
dbr.FileNames.Add(fileName);
}
}
}
public void Read()
{
// read all database records into data structure
using (StreamReader sr = new StreamReader(databaseFile))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
string partNumber = line.Split(':')[0].Trim();
if (partNumber[0] == ''"')
partNumber = partNumber.Substring(1, partNumber.Length - 2);
string[] files = line.Split(new string[]{":"}, StringSplitOptions.None)[1].Split(new string[]{","}, StringSplitOptions.RemoveEmptyEntries);
List<string> fileNumbers = new List<string>();
foreach (String file in files)
{
if (!string.IsNullOrWhiteSpace(file))
{
fileNumbers.Add(file.Trim());
}
}
records.Add(new DataBaseRecord(partNumber, fileNumbers));
}
}
}
public void Write()
{
// write out database using the records
var sortedRecords = from x in records orderby x.PartNumber select x;
using (StreamWriter sw = new StreamWriter(databaseFile))
{
foreach (DataBaseRecord record in sortedRecords)
{
string line = record.PartNumber + ": ";
for (int index = 0; index < record.FileNames.Count; index++)
{
line += record.FileNames[index];
if (index < record.FileNames.Count - 1)
line += ", ";
}
sw.WriteLine(line);
}
}
}
}
static void Main(string[] args)
{
// replace with name of your database
DataBase db = new DataBase(@"C:'Users'jondoe'Desktop'DataBase.txt");
db.Read();
// replace with list of your parts files
string[] partsFiles = new string[] { @"C:'Users'jondoe'Desktop'parts.txt" };
foreach (string partsFile in partsFiles)
{
using (StreamReader sr = new StreamReader(partsFile))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
string partNumber = line.Split(new string[] { "," }, StringSplitOptions.None)[7];
if (partNumber[0] == ''"')
partNumber = partNumber.Substring(1, partNumber.Length - 2);
db.AddRecord(partNumber, Path.GetFileNameWithoutExtension(partsFile));
}
}
}
db.Write();
}
}
}
编辑
如果您想要一个静态数据库,并且希望允许用户选择部件文件,那么您可以在按钮单击事件中完成此操作:
private void btnOpenFile_Click(object sender, EventArgs e)
{
DataBase db = new DataBase(@"C:'Users'JonDoe'Desktop'DataBase.txt");
db.Read();
using (OpenFileDialog ofd = new OpenFileDialog())
{
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
using (StreamReader sr = new StreamReader(ofd.FileName))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
string partNumber = line.Split(new string[] { "," }, StringSplitOptions.None)[7];
if (partNumber[0] == ''"')
partNumber = partNumber.Substring(1, partNumber.Length - 2);
db.AddRecord(partNumber, Path.GetFileNameWithoutExtension(ofd.FileName));
}
}
db.Write();
}
}
}
请勿自行解析CSV。使用FileHelpers库。可能会有很多异常,而FileHelpers可以很好地处理这些异常。
其次,你做了足够多的数据操作,一个简单的数据库可能会有所帮助。也许是SQL Express,或者一个单文件嵌入式数据库(SQL Server Compact, SQLite)。
最后,要手动执行此操作,您只需在内存中构建表。您真正拥有的是零件号和文件之间的多对多关系。你有两个表,中间有一个连接表。
现在,由于"filename"在您的示例中只有一个属性(filename),因此它可以作为附加列添加到连接表中。所以有两张表。第二个看起来像
JoinTable
-------------------
PartNum | Varchar
Filename| Varchar
您已经拥有的第一张表。
因此,如果您使用List<List<string>>
在内存中复制这两个表,那么您应该能够使用LINQ毫不费力地完成此操作。虽然我个人会构建新的类或至少是结构来表示这两个表元组。
这里是一个快速运行…它肯定可以改进,但这只是一个开始:)
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
public class FileIo
{
private Dictionary<int, CommaDelimitedStringCollection> dataBase;
private const string DATABASE_PATH = @"D:'Temp'Test'DATABASE.txt";
public void Run()
{
var files = new List<string> { @"D:'Temp'Test'Test1.txt", @"D:'Temp'Test'Test2.txt", @"D:'Temp'Test'Test3.txt" };
dataBase = GetDatabase();
foreach (var file in files)
{
Search(file, GetPartNumbers(file));
}
WriteFileContents(DATABASE_PATH, BuildPartsDbStr());
}
private void Search(string fileName, List<int> partNums)
{
foreach (var partNum in partNums)
{
var path = Path.GetFileNameWithoutExtension(fileName);
if (dataBase.Keys.Contains(partNum))
{
dataBase[partNum].Add(path);
}
else
{
dataBase.Add(partNum, new CommaDelimitedStringCollection { path });
}
}
}
private string BuildPartsDbStr()
{
var sb = new StringBuilder();
var db = from x in dataBase orderby x.Key select x;
foreach (var record in db)
{
sb.AppendLine(string.Format("{0}: {1}", record.Key, record.Value));
}
return sb.ToString();
}
private Dictionary<int, CommaDelimitedStringCollection> GetDatabase()
{
var contents = GetFileContents(DATABASE_PATH);
var commaStr = new CommaDelimitedStringCollection();
var db = new Dictionary<int, CommaDelimitedStringCollection>();
var id = 0;
var collection = new CommaDelimitedStringCollection();
for (var i = 0; i < commaStr.Count; i++ )
{
var str = commaStr[i];
if (str.Contains(":"))
{
collection.Add(str.Split(':')[1]);
if (i > 0) db.Add(id, collection);
collection = new CommaDelimitedStringCollection();
id = int.Parse(str.Split(':')[0]);
}
else
{
collection.Add(str);
}
}
return db;
}
private List<int> GetPartNumbers(string filePath)
{
var contents = GetFileContents(filePath);
var commaStr = new CommaDelimitedStringCollection();
var result = new List<int>();
commaStr.AddRange(contents.Split(','));
for(var i = 7; i < commaStr.Count; i += 15)
{
result.Add(int.Parse(commaStr[i].Replace("'"", string.Empty)));
}
return result;
}
private string GetFileContents(string path)
{
using (var stream = new StreamReader(path))
{
//yes I know this is evil - I don't have all night :P
return stream.ReadToEnd();
}
}
private void WriteFileContents(string path, string contents)
{
using (var stream = new StreamWriter(path, false))
{
stream.Write(contents);
stream.Flush();
}
}
}
}