C# - 读取、编辑和保存固定长度文件
C# - Read, Edit & Save FixedLength file
我需要读取 FixedLenght 文件,编辑其中的一些数据,然后将该文件保存到某个位置。这个应该做所有这些的小应用程序应该每 2 小时 运行。
这是文件的例子:
14000 美国 A111 78900
14000 美国 A222 78900
14000 美国 A222 78900
我需要查找 A111 和 A222 等数据,并将所有 A111 替换为例如 A555。我试过使用 TextFieldParser 但没有任何运气......这是我的代码。我能够获取数组元素,但我不确定下一步该做什么...
using (TextFieldParser parser =
FileSystem.OpenTextFieldParser(sourceFile))
{
parser.TextFieldType = FieldType.FixedWidth;
parser.FieldWidths = new int[] { 6, 3, 5, 5 };
while (!parser.EndOfData)
{
try
{
string[] fields = parser.ReadFields();
foreach (var f in fields)
{
Console.WriteLine(f);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
这是 Berkouz 的解决方案,但仍然存在问题,当保存到文件时,数组的项目不会在输出中被替换。代码:
string[] rows = File.ReadAllLines(sourceFile);
foreach (var row in rows)
{
string[] elements = row.Split(' ');
for (int i = 0; i < elements.Length; i++)
{
if (elements.GetValue(i).ToString() == "A111") {
elements.SetValue("A555", i);
}
}
}
var destFile = targetPath.FullName + "\" + "output.txt";
File.WriteAllLines(destFile, rows);
这看起来像一个 AB 问题。如果这是一次性的事情,我建议您改用 sed
。
调用很简单:sed -e 's/A111/A555/g'
如果您的文件内容更复杂,您可以使用 awk
、perl
pcre 正则表达式功能。
如果这实际上不是一次性的事情并且您想用 C# 编写它,您可以:
A) 使用 System.IO.File.ReadAllLines()
,使用 string.Split()
拆分文本,使用 string.Replace()
替换你想要的项目,然后使用 WriteAllLines()
写回
B) 使用 MemoryMappedFile
。这样,您就不必担心写任何东西。但它往往会变得有点尖锐,您应该小心 BOM。
还有很多其他方法,这些是 easy/slow/clean 和 fast/efficient/ugly 代码的两端。
注意行 [rowIndex] 分配给的行。这是因为字符串不变性迫使替换和类似函数具有输出值(而不是修改它们的输入),您必须将其分配回数据存储(无论它是什么,在这种情况下是一个数组)。
var rows = File.ReadAllLines(sourcefile);
for (int rowIndex = 0; rowIndex != rows.Length; rowIndex++)
rows[rowIndex] = rows[rowIndex].Replace("A111", "A555");
File.WriteAllLines(destFile, rows);
我需要读取 FixedLenght 文件,编辑其中的一些数据,然后将该文件保存到某个位置。这个应该做所有这些的小应用程序应该每 2 小时 运行。
这是文件的例子:
14000 美国 A111 78900
14000 美国 A222 78900
14000 美国 A222 78900
我需要查找 A111 和 A222 等数据,并将所有 A111 替换为例如 A555。我试过使用 TextFieldParser 但没有任何运气......这是我的代码。我能够获取数组元素,但我不确定下一步该做什么...
using (TextFieldParser parser =
FileSystem.OpenTextFieldParser(sourceFile))
{
parser.TextFieldType = FieldType.FixedWidth;
parser.FieldWidths = new int[] { 6, 3, 5, 5 };
while (!parser.EndOfData)
{
try
{
string[] fields = parser.ReadFields();
foreach (var f in fields)
{
Console.WriteLine(f);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
这是 Berkouz 的解决方案,但仍然存在问题,当保存到文件时,数组的项目不会在输出中被替换。代码:
string[] rows = File.ReadAllLines(sourceFile);
foreach (var row in rows)
{
string[] elements = row.Split(' ');
for (int i = 0; i < elements.Length; i++)
{
if (elements.GetValue(i).ToString() == "A111") {
elements.SetValue("A555", i);
}
}
}
var destFile = targetPath.FullName + "\" + "output.txt";
File.WriteAllLines(destFile, rows);
这看起来像一个 AB 问题。如果这是一次性的事情,我建议您改用 sed
。
调用很简单:sed -e 's/A111/A555/g'
如果您的文件内容更复杂,您可以使用 awk
、perl
pcre 正则表达式功能。
如果这实际上不是一次性的事情并且您想用 C# 编写它,您可以:
A) 使用 System.IO.File.ReadAllLines()
,使用 string.Split()
拆分文本,使用 string.Replace()
替换你想要的项目,然后使用 WriteAllLines()
写回
B) 使用 MemoryMappedFile
。这样,您就不必担心写任何东西。但它往往会变得有点尖锐,您应该小心 BOM。
还有很多其他方法,这些是 easy/slow/clean 和 fast/efficient/ugly 代码的两端。
注意行 [rowIndex] 分配给的行。这是因为字符串不变性迫使替换和类似函数具有输出值(而不是修改它们的输入),您必须将其分配回数据存储(无论它是什么,在这种情况下是一个数组)。
var rows = File.ReadAllLines(sourcefile);
for (int rowIndex = 0; rowIndex != rows.Length; rowIndex++)
rows[rowIndex] = rows[rowIndex].Replace("A111", "A555");
File.WriteAllLines(destFile, rows);