是否可以在 C# 中读取和写入同一个文本文件
Is it possible to read from and write to the same text file in C#
情况是这样的。我有超过 1500 个 SQL(文本)文件,其中包含“在 CREATE TABLE 语句后向某些用户授予某些 table 某些特权。我需要将它们从原始文件中删除并将 GRANT 语句放在它们自己的文件中。有时 GRANT 在一行上,有时它们分成多行。例如:
GRANT SELECT ON XYZ.TABLE1 TO MYROLE1 ;
GRANT
SELECT ON XYZ.TABLE1 TO MYROLE2 ;
GRANT
DELETE,
INSERT,
SELECT,
UPDATE ON XYZ.TABLE1 TO MYROLE3;
我通读文件直到到达 GRANT,然后构建一个字符串,其中包含从 GRANT 到分号的文本,然后我将其写到另一个文件。我有一个用 Delphi (Pascal) 编写的应用程序,这部分效果很好。我想做的是在阅读并处理完我想要的行之后,我想从原始文本文件中删除该行。我无法在 Delphi 中执行此操作。唯一的解决方案是逐行读取文件并将文件写回另一个文件,不包括我不想要的行,同时将 GRANTS 写入另一个文件。然后删除原来的并重命名新的。太多的处理和风险。
我查看了在 C# 中使用 StreamReader 和 StreamWriter,但情况似乎与 Delphi 类似。我可以读取或写入,但我不能同时对同一个文件执行这两项操作。
如果有任何意见或建议,我将不胜感激。
谢谢
如果您认为 "way too much processing and risk" 在 生成一个新的临时文件而没有您不想要的行并替换原始文件: 那么请考虑您的替代方案'重新希望实现。
Line 1
Line 2
Delete this line
+-->Line 4
| Line 5
|
+- Read position marker after reading line to be deleted
如果在阅读时立即删除该行,则后面的行必须移回删除第 3 行后留下的 "empty space"。为了确保您下次阅读 "Line 4",您必须 回溯 您的 read-position-marker。回溯的正确数量是多少? 可变长度的"line",或删除行的字符数?
你认为的"risky"选项实际上是安全选项!
如果你想在处理时删除,你可以使用给你那种印象的抽象。但是您失去了流处理的好处,并没有真正消除您最初担心的任何风险。
例如将整个文件加载到字符串列表中;例如数组、向量或 TStringList
(在 Delphi 中)。迭代列表并删除不需要的项目。最后将列表保存回文件。
这种方法有以下缺点:
- 潜在的高内存开销,因为您加载整个文件而不是流的小缓冲区。
- 您有 mid-process 失败且无法恢复的风险,因为您的工作是 all-or-nothing.
- 您必须处理您选择用来保存字符串列表的特定容器的细微差别。
- 在某些情况下(例如
TStringList
),您可能仍需要以与之前描述类似的方式回溯您的位置标记。
- 对于数组,每次删除内容时都必须将所有行复制回 1 个位置,这会带来巨大的性能成本。 (同样的事情发生在
TStringList
中,尽管它对你隐藏了。)
- 只要您修改列表,某些容器的迭代器就会失效。这意味着您在任何情况下都必须复制到没有 'deleted lines' 的新列表。 更多内存开销。
总之,采取安全选项。使用单独的读写流;写入临时文件,完成后重命名。 它会让你省去头痛。
情况是这样的。我有超过 1500 个 SQL(文本)文件,其中包含“在 CREATE TABLE 语句后向某些用户授予某些 table 某些特权。我需要将它们从原始文件中删除并将 GRANT 语句放在它们自己的文件中。有时 GRANT 在一行上,有时它们分成多行。例如:
GRANT SELECT ON XYZ.TABLE1 TO MYROLE1 ;
GRANT
SELECT ON XYZ.TABLE1 TO MYROLE2 ;
GRANT
DELETE,
INSERT,
SELECT,
UPDATE ON XYZ.TABLE1 TO MYROLE3;
我通读文件直到到达 GRANT,然后构建一个字符串,其中包含从 GRANT 到分号的文本,然后我将其写到另一个文件。我有一个用 Delphi (Pascal) 编写的应用程序,这部分效果很好。我想做的是在阅读并处理完我想要的行之后,我想从原始文本文件中删除该行。我无法在 Delphi 中执行此操作。唯一的解决方案是逐行读取文件并将文件写回另一个文件,不包括我不想要的行,同时将 GRANTS 写入另一个文件。然后删除原来的并重命名新的。太多的处理和风险。
我查看了在 C# 中使用 StreamReader 和 StreamWriter,但情况似乎与 Delphi 类似。我可以读取或写入,但我不能同时对同一个文件执行这两项操作。
如果有任何意见或建议,我将不胜感激。
谢谢
如果您认为 "way too much processing and risk" 在 生成一个新的临时文件而没有您不想要的行并替换原始文件: 那么请考虑您的替代方案'重新希望实现。
Line 1 Line 2 Delete this line +-->Line 4 | Line 5 | +- Read position marker after reading line to be deleted
如果在阅读时立即删除该行,则后面的行必须移回删除第 3 行后留下的 "empty space"。为了确保您下次阅读 "Line 4",您必须 回溯 您的 read-position-marker。回溯的正确数量是多少? 可变长度的"line",或删除行的字符数?
你认为的"risky"选项实际上是安全选项!
如果你想在处理时删除,你可以使用给你那种印象的抽象。但是您失去了流处理的好处,并没有真正消除您最初担心的任何风险。
例如将整个文件加载到字符串列表中;例如数组、向量或 TStringList
(在 Delphi 中)。迭代列表并删除不需要的项目。最后将列表保存回文件。
这种方法有以下缺点:
- 潜在的高内存开销,因为您加载整个文件而不是流的小缓冲区。
- 您有 mid-process 失败且无法恢复的风险,因为您的工作是 all-or-nothing.
- 您必须处理您选择用来保存字符串列表的特定容器的细微差别。
- 在某些情况下(例如
TStringList
),您可能仍需要以与之前描述类似的方式回溯您的位置标记。 - 对于数组,每次删除内容时都必须将所有行复制回 1 个位置,这会带来巨大的性能成本。 (同样的事情发生在
TStringList
中,尽管它对你隐藏了。) - 只要您修改列表,某些容器的迭代器就会失效。这意味着您在任何情况下都必须复制到没有 'deleted lines' 的新列表。 更多内存开销。
- 在某些情况下(例如
总之,采取安全选项。使用单独的读写流;写入临时文件,完成后重命名。 它会让你省去头痛。