C#能否同时读写同一文本文件?及批量处理SQL文件GRANT语句方案
嘿,我来帮你解决这两个问题:
问题1:C#中能否同时对同一个文本文件进行读取和写入操作?
答案是可以,但需要注意文件访问权限和锁机制——直接用默认方式打开同一个文件进行读写,大概率会因为文件独占锁抛出异常。这里推荐两种稳妥的实现方式:
方式1:通过FileStream设置共享权限
你可以用File.Open创建流时,指定FileAccess.ReadWrite和合适的FileShare参数,允许同时读写操作,但要手动控制指针位置,避免读写冲突:
using (var stream = File.Open("example.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { // 读取全部内容 var reader = new StreamReader(stream); string content = reader.ReadToEnd(); // 将指针移回文件开头(准备覆盖写入) stream.Seek(0, SeekOrigin.Begin); // 写入修改后的内容 var writer = new StreamWriter(stream); writer.Write(content.Replace("old_text", "new_text")); // 截断原文件中多余的内容(如果新内容比原内容短) stream.SetLength(stream.Position); }
方式2:先读入内存再写入(更安全推荐)
对于大多数场景(比如你的SQL文件处理),更推荐先把文件内容全部读入内存,修改后再覆盖写入文件。这种方式避免了并发读写的冲突,代码也更简洁:
// 读取文件到内存 string content = File.ReadAllText("target.sql"); // 修改内容(比如移除GRANT语句) string cleanedContent = RemoveGrantStatements(content); // 覆盖写入原文件 File.WriteAllText("target.sql", cleanedContent);
问题2:批量移除SQL文件中的GRANT语句并单独保存
针对你1500+ SQL文件的处理需求,我们可以用C#结合正则表达式实现批量操作,核心思路和代码如下:
核心流程
- 遍历指定目录下的所有
.sql文件 - 对每个文件:
- 读取全部内容
- 用正则匹配并提取所有
GRANT语句(支持单行/跨行分布) - 移除原内容中的
GRANT语句 - 将清理后的内容写回原文件
- 将提取的
GRANT语句写入对应新文件(例如原文件名_Grants.sql)
关键正则表达式
因为GRANT语句可能跨行,我们需要启用Singleline模式让.匹配换行符,同时忽略SQL的大小写特性:
// 匹配GRANT语句:从GRANT开头到分号结束,支持跨行 var grantRegex = new Regex(@"\bGRANT\s+.+?;\s*", RegexOptions.IgnoreCase | RegexOptions.Singleline);
这个正则会匹配所有以GRANT开头、到第一个;结束的内容,包括中间包含换行的情况,同时兼容SQL不区分大小写的特性。
完整代码实现
using System; using System.IO; using System.Text.RegularExpressions; using System.Linq; class SqlGrantBatchProcessor { static void Main(string[] args) { // 替换为你的SQL文件存放目录 string sqlRootDir = @"C:\Your_Sql_Files_Path"; // 获取目录下所有.sql文件(如需处理子目录,把TopDirectoryOnly改成AllDirectories) var sqlFiles = Directory.EnumerateFiles(sqlRootDir, "*.sql", SearchOption.TopDirectoryOnly); // 初始化GRANT语句正则 var grantRegex = new Regex(@"\bGRANT\s+.+?;\s*", RegexOptions.IgnoreCase | RegexOptions.Singleline); foreach (var filePath in sqlFiles) { try { // 读取文件内容(注意:如果你的文件是GBK等非UTF8编码,需指定Encoding,比如Encoding.GetEncoding("GB2312")) string originalContent = File.ReadAllText(filePath); // 提取所有GRANT语句 var grantMatches = grantRegex.Matches(originalContent); string grantContent = string.Join(Environment.NewLine, grantMatches.Cast<Match>().Select(m => m.Value.Trim())); // 移除原内容中的GRANT语句 string cleanedContent = grantRegex.Replace(originalContent, string.Empty).Trim(); // 写回清理后的原文件 File.WriteAllText(filePath, cleanedContent); // 生成GRANT文件路径并写入(仅当提取到内容时) if (!string.IsNullOrEmpty(grantContent)) { string grantFilePath = Path.Combine( Path.GetDirectoryName(filePath), $"{Path.GetFileNameWithoutExtension(filePath)}_Grants.sql" ); File.WriteAllText(grantFilePath, grantContent); Console.WriteLine($"✅ 处理完成:{filePath} | 已提取GRANT到{grantFilePath}"); } else { Console.WriteLine($"ℹ️ 处理完成:{filePath} | 未找到GRANT语句"); } } catch (Exception ex) { Console.WriteLine($"❌ 处理文件{filePath}出错:{ex.Message}"); } } Console.WriteLine("\n所有文件处理完毕!"); Console.ReadLine(); } }
注意事项
- 编码兼容性:如果你的SQL文件不是UTF8编码,需要在
File.ReadAllText和File.WriteAllText中指定对应编码(比如Encoding.ASCII或Encoding.GetEncoding("GBK"))。 - 备份文件:处理前请务必备份所有SQL文件,避免意外导致数据丢失。
- 正则微调:如果你的GRANT语句包含特殊格式(比如带引号的表名/用户名),当前正则已能兼容,若有特殊场景可再调整正则规则。
内容的提问来源于stack exchange,提问作者Richard Anderson
相关产品推荐
相关产品推荐

