读取文本文件(txt、csv、log、制表符、定长)






4.39/5 (21投票s)
本文主要关注如何高效地读取文本文件。它包括日志、csv、制表符分隔、定长文件等。我们不使用 StreamReader(.NET)/FileSystemObject(VB 6.0),而是将文件视为数据库表,通过查询来读取数据。
引言
在许多情况下,我们需要从文本文件(*.txt、*.CSV、*.tab)中读取和处理数据。最常用的方法是使用 StreamReader
(.NET)/FileSystemObject
(VB 6.0)逐行读取文件。
假设我们能够将文件视为数据库表并处理数据,那么上述方法存在许多缺点。
一些缺点包括:
- 连接环境。在进程完成之前锁定文件。
- 我们必须单独分割每一行才能获取单个数据列。处理包含逗号作为其数据一部分的行很困难。
示例:“是,逗号在这里”,2,“你好,另一个逗号”,4,5,6 - 在读取该行并开始处理之前,我们没有选项来过滤数据。
- 计算文件中的记录数或特定类型的记录数需要读取整个文件。
我们可以列出许多此类缺点。使用数据库表查询的所有优点都可以被视为逐行读取的缺点。
现在,我们能否将文本文件视为数据库表来读取?
如果答案是否定的,我们就不会讨论这个话题。是的,我们可以将文件视为数据库表来读取,并且可以轻松克服上述所有缺点。
读取数据
这就像连接到数据库并从数据库表中查询数据一样简单。在这种情况下,我们将文本文件视为表,将包含的文件夹视为数据库。
读取数据的步骤如下:
- 打开数据库连接
注意:连接字符串非常重要。它取决于我们尝试读取的文件类型。我们将在本文后面讨论这一点。 - 使用基本查询语言获取结果集。
- 循环遍历记录并读取字段。
C# 代码
DataSet myData = new DataSet();
string myXML;
string strFilePath = "C:\\";
string mySelectQuery = "SELECT * FROM SampleFile.CSV";
OleDbConnection myConnection = new OleDbConnection
("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\;" +
"Extended Properties=\"text;HDR=YES;FMT=Delimited\"");
OleDbDataAdapter dsCmd = new OleDbDataAdapter(mySelectQuery, myConnection);
//Fill the DataSet object
dsCmd.Fill(myData, "CustomerOwners");
//Create a XML document with the table data
myData.WriteXml("D:\\TestXML.xml");
myConnection.Close();
VB 6.0 代码
'Set the database connection
objConnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & strFilePath & ";" & _
"Extended Properties=""text;HDR=YES;FMT=Delimited"""
'Query from the file assuming it as a database table
objRecordset.Open "SELECT * FROM " & fileName, _
objConnection, adOpenStatic, adLockOptimistic, adCmdText
'Loop through the records and insert in to the table
Do Until objRecordset.EOF
Debug.Print objRecordset.Fields.Item("Number")
Debug.Print objRecordset.Fields.Item("Name")
objRecordset.MoveNext
Loop
我们将文本文件视为数据库表并将其上传到数据库。让我们看看这种方法的优点:
- 此过程速度很快。
- 我们需要注意的第一点是它处理数据行和分割数据的方式。假设文本列中包含逗号(上面列出的缺点的第 2 点),此过程会自动处理这种情况。我们无需单独处理。
- 如果我们给出选择条件,我们可以从文件中选择特定行集。
示例:“SELECT * FROM SampleFile1.CSV WHERE Number >= 3
” - 此时,可以清楚地理解,我们可以在查询中使用
WHERE
、HAVING
或GROUP BY
子句,这有时非常有帮助。
例如:“SELECT Number, Count(Name) FROM SampleFile1.CSV GROUP BY Number HAVING Count(Name) >= 1
” - 在读取文件中的所有数据后,我们可以根据需要过滤数据。这可以使用
RowFilter
/Filter
属性或DataView
/RecordSet
来完成。正如我所说,一旦我们将数据读入Dataset
/RecordSet
,我们就可以对其执行所有可以执行的操作,包括过滤、排序等。
其他文件格式
我们讨论了如何读取逗号分隔值(CSV)文件。这种方法如何处理制表符分隔文件和定长文件?
一切取决于我们提供的连接字符串。让我们在此处查看连接字符串的详细信息。
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\FolderName;
Extended Properties="text;HDR=YES;FMT=Delimited
提供程序 – 这代表数据库的类型。我们使用 OLEDB 连接类型。
数据源 – 文件夹被视为数据库。
扩展属性 – 这些属性将定义我们希望如何读取文件。
- 其中第一部分定义了文件类型。在我们的例子中,尽管文件格式可以归类为逗号分隔、制表符分隔或定长数据,但它们都是简单的文本。如果我们要读取 Excel 文件,我们会使用 Excel x.x,其中 x.x 是版本号。
- HDR(Header)– 用于指定是否存在标题。YES – 输入文件的第一行被视为标题,其余行被视为数据。NO – 从第一行开始视为数据。
- FMT(Format)– 指定格式类型。它可以具有以下值:
分隔
文件被视为逗号分隔文件。逗号是默认分隔符。 Delimited(x)
文件被视为以分隔符“x”分隔的文件。 TabDelimited
文件被视为制表符分隔的文件。 FixedLength
读取具有指定字段固定长度的数据。您必须使用 Col1
、Col2
等属性指定列的宽度和类型。有关更多信息,请参阅 MSDN。
如果指定的格式是“Delimited
”,则默认字符是逗号(,)。它存储在注册表中。您可以在注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Text\Format 下进行更改。
正如大家所说,不要随意修改注册表。Microsoft 提供了一个替代方法,即提供 Schema.ini 文件。如果我们读取 FixedLength
文件,我们必须使用 Schema.ini 文件。我们在 schema 文件中指定字段的长度。
从多个文件读取
如果您有多个文件,并且需要根据公共列合并或过滤数据,我们可以像在 SQL 中一样进行操作。我们可以连接表并获取合并后的数据。请记住,输出将是两个文件中行的 CROSS JOIN
。确保根据公共列过滤数据。
示例
SampleFile1.CSV –(EmpID
、Name
、Address
)
SampleFile2.CSV –(EmpID
、Salary
、Month
)
//Where clause is used to get ‘Natural Join’
string mySelectQuery = "SELECT * FROM SampleFile.CSV As Sample1, _
SampleFile2.CSV As Sample2 " + _
"Where Sample1.Number=Sample2.Number";
'Where clause is used to get ‘Natural Join’
objRecordset.Open "SELECT * FROM SampleFile.CSV As Sample1, _
SampleFile2.CSV As Sample2 " & _
"Where Sample1.Number=Sample2.Number", _
objConnection, adOpenStatic, adLockOptimistic, adCmdText
请注意,在 join
查询中,尤其是在表具有相同名称的列时,需要使用别名(SampleFile.CSV AS Sample1
)。在我们的例子中,表名(文件名)之间有点(.)。因此,查询解析器可能会被表中的点误导,并将“CSV.Number
”视为列名。
历史
- 2008年6月9日:初始帖子