如何从C#中的文本文件中删除一行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/668907/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to delete a line from a text file in C#?
提问by alinpopescu
I have a problem: how can I delete a line from a text file in C#?
我有一个问题:如何从 C# 中的文本文件中删除一行?
采纳答案by Sascha
Read the file, remove the line in memory and put the contents back to the file (overwriting). If the file is large you might want to read it line for line, and creating a temp file, later replacing the original one.
读取文件,删除内存中的行并将内容放回文件(覆盖)。如果文件很大,您可能希望逐行读取它,并创建一个临时文件,稍后替换原始文件。
回答by Jon Skeet
I agree with John Saunders, this isn't really C# specific. However, to answer your question: you basically need to rewrite the file. There are two ways you can do this.
我同意 John Saunders 的观点,这并不是 C# 特有的。但是,要回答您的问题:您基本上需要重写文件。有两种方法可以做到这一点。
- Read the whole file into memory (e.g. with
File.ReadAllLines
) - Remove the offending line (in this case it's probably easiest to convert the string array into a
List<string>
then remove the line) - Write all the rest of the lines back (e.g. with
File.WriteAllLines
) - potentially convert theList<string>
into a string array again usingToArray
- 将整个文件读入内存(例如使用
File.ReadAllLines
) - 删除有问题的行(在这种情况下,将字符串数组转换为 a
List<string>
然后删除该行可能是最简单的) - 将所有其余的行写回(例如使用
File.WriteAllLines
) - 可能List<string>
使用再次将其转换为字符串数组ToArray
That means you have to know that you've got enough memory though. An alternative:
这意味着你必须知道你有足够的内存。替代:
- Open both the input file and a new output file (as a
TextReader
/TextWriter
, e.g. withFile.OpenText
andFile.CreateText
) - Read a line (
TextReader.ReadLine
) - if you don't want to delete it, write it to the output file (TextWriter.WriteLine
) - When you've read all the lines, close both the reader and the writer (if you use
using
statements for both, this will happen automatically) - If you want to replace the input with the output, delete the input file and then move the output file into place.
- 打开输入文件和新的输出文件(作为
TextReader
/TextWriter
,例如使用File.OpenText
和File.CreateText
) - 读取一行 (
TextReader.ReadLine
) - 如果您不想删除它,请将其写入输出文件 (TextWriter.WriteLine
) - 当你读完所有的行后,关闭 reader 和 writer(如果你
using
对两者都使用语句,这将自动发生) - 如果要用输出替换输入,请删除输入文件,然后将输出文件移动到位。
回答by Markus Olsson
For verylarge files I'd do something like this
对于非常大的文件,我会做这样的事情
string tempFile = Path.GetTempFileName();
using(var sr = new StreamReader("file.txt"))
using(var sw = new StreamWriter(tempFile))
{
string line;
while((line = sr.ReadLine()) != null)
{
if(line != "removeme")
sw.WriteLine(line);
}
}
File.Delete("file.txt");
File.Move(tempFile, "file.txt");
UpdateI originally wrote this back in 2009 and I thought it might be interesting with an update. Today you could accomplish the above using LINQ and deferred execution
更新我最初是在 2009 年写的,我认为更新可能会很有趣。今天,您可以使用LINQ 和延迟执行完成上述操作
var tempFile = Path.GetTempFileName();
var linesToKeep = File.ReadLines(fileName).Where(l => l != "removeme");
File.WriteAllLines(tempFile, linesToKeep);
File.Delete(fileName);
File.Move(tempFile, fileName);
The code above is almost exactly the same as the first example, reading line by line and while keeping a minimal amount of data in memory.
上面的代码与第一个示例几乎完全相同,逐行读取,同时在内存中保留最少的数据。
A disclaimer might be in order though. Since we're talking about text files here you'd very rarely have to use the disk as an intermediate storage medium. If you're not dealing with very large log files there should be no problem reading the contents into memory instead and avoid having to deal with the temporary file.
不过,可能需要免责声明。由于我们在这里讨论的是文本文件,因此您很少需要将磁盘用作中间存储介质。如果您不处理非常大的日志文件,那么将内容读入内存应该没有问题,并且不必处理临时文件。
File.WriteAllLines(fileName,
File.ReadLines(fileName).Where(l => l != "removeme").ToList());
Note that The .ToList
is crucial here to force immediate execution. Also note that all the examples assume the text files are UTF-8 encoded.
请注意,.ToList
这里对于强制立即执行至关重要。另请注意,所有示例都假定文本文件是 UTF-8 编码的。
回答by Adam Hawes
I'd very simply:
我很简单:
- Open the file for read/write
- Read/seek through it until the start of the line you want to delete
- Set the write pointer to the current read pointer
- Read through to the end of the line we're deleting and skip the newline delimiters (counting the number of characters as we go, we'll call it nline)
- Read byte-by-byte and write each byte to the file
- When finished truncate the file to (orig_length - nline).
- 打开文件进行读/写
- 阅读/查找它直到您要删除的行的开头
- 将写指针设置为当前读指针
- 通读到我们要删除的行的末尾并跳过换行符(计算字符数,我们将其称为 nline)
- 逐字节读取并将每个字节写入文件
- 完成后将文件截断为 (orig_length - nline)。
回答by H?vard Fj?r
I extended what Markus Olsson suggested, and came up with this class that adds multiple search strings and a couple of event:
我扩展了 Markus Olsson 的建议,并提出了这个添加多个搜索字符串和几个事件的类:
public static class TextLineRemover
{
public static void RemoveTextLines(IList<string> linesToRemove, string filename, string tempFilename)
{
// Initial values
int lineNumber = 0;
int linesRemoved = 0;
DateTime startTime = DateTime.Now;
// Read file
using (var sr = new StreamReader(filename))
{
// Write new file
using (var sw = new StreamWriter(tempFilename))
{
// Read lines
string line;
while ((line = sr.ReadLine()) != null)
{
lineNumber++;
// Look for text to remove
if (!ContainsString(line, linesToRemove))
{
// Keep lines that does not match
sw.WriteLine(line);
}
else
{
// Ignore lines that DO match
linesRemoved++;
InvokeOnRemovedLine(new RemovedLineArgs { RemovedLine = line, RemovedLineNumber = lineNumber});
}
}
}
}
// Delete original file
File.Delete(filename);
// ... and put the temp file in its place.
File.Move(tempFilename, filename);
// Final calculations
DateTime endTime = DateTime.Now;
InvokeOnFinished(new FinishedArgs {LinesRemoved = linesRemoved, TotalLines = lineNumber, TotalTime = endTime.Subtract(startTime)});
}
private static bool ContainsString(string line, IEnumerable<string> linesToRemove)
{
foreach (var lineToRemove in linesToRemove)
{
if(line.Contains(lineToRemove))
return true;
}
return false;
}
public static event RemovedLine OnRemovedLine;
public static event Finished OnFinished;
public static void InvokeOnFinished(FinishedArgs args)
{
Finished handler = OnFinished;
if (handler != null) handler(null, args);
}
public static void InvokeOnRemovedLine(RemovedLineArgs args)
{
RemovedLine handler = OnRemovedLine;
if (handler != null) handler(null, args);
}
}
public delegate void Finished(object sender, FinishedArgs args);
public class FinishedArgs
{
public int TotalLines { get; set; }
public int LinesRemoved { get; set; }
public TimeSpan TotalTime { get; set; }
}
public delegate void RemovedLine(object sender, RemovedLineArgs args);
public class RemovedLineArgs
{
public string RemovedLine { get; set; }
public int RemovedLineNumber { get; set; }
}
Usage:
用法:
TextLineRemover.OnRemovedLine += (o, removedLineArgs) => Console.WriteLine(string.Format("Removed \"{0}\" at line {1}", removedLineArgs.RemovedLine, removedLineArgs.RemovedLineNumber));
TextLineRemover.OnFinished += (o, finishedArgs) => Console.WriteLine(string.Format("{0} of {1} lines removed. Time used: {2}", finishedArgs.LinesRemoved, finishedArgs.TotalLines, finishedArgs.TotalTime.ToString()));
TextLineRemover.RemoveTextLines(new List<string> { "aaa", "bbb" }, fileName, fileName + ".tmp");
回答by Prakash Rajendran
To remove an item from a text file, first move all the text to a list and remove whichever item you want. Then write the text stored in the list into a text file:
要从文本文件中删除项目,首先将所有文本移动到列表中,然后删除您想要的任何项目。然后将存储在列表中的文本写入文本文件:
List<string> quotelist=File.ReadAllLines(filename).ToList();
string firstItem= quotelist[0];
quotelist.RemoveAt(0);
File.WriteAllLines(filename, quotelist.ToArray());
return firstItem;
回答by Leonhard P.
I wrote a method to delete lines from files.
我写了一个方法来从文件中删除行。
This program uses using System.IO
.
该程序使用using System.IO
.
See my code:
看我的代码:
void File_DeleteLine(int Line, string Path)
{
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(Path))
{
int Countup = 0;
while (!sr.EndOfStream)
{
Countup++;
if (Countup != Line)
{
using (StringWriter sw = new StringWriter(sb))
{
sw.WriteLine(sr.ReadLine());
}
}
else
{
sr.ReadLine();
}
}
}
using (StreamWriter sw = new StreamWriter(Path))
{
sw.Write(sb.ToString());
}
}
回答by Marty Brant
Why can't use this? First, create an array:
为什么不能用这个?首先,创建一个数组:
string[] lines = File.ReadAllLines(openFileDialog1.FileName);
Then look up the line you need to delete and replace it with "" :
然后查找您需要删除的行并将其替换为 "" :
lines[x].Replace(lines[x], "");
Done!
完毕!
回答by Joel Wiklund
Remove a block of code from multiple files
从多个文件中删除一个代码块
To expand on @Markus Olsson's answer, I needed to remove a block of code from multiple files. I had problems with Swedish characters in a core project, so I needed to install System.Text.CodePagesEncodingProvider nuget package and use System.Text.Encoding.GetEncoding(1252) instead of System.Text.Encoding.UTF8.
为了扩展@Markus Olsson 的回答,我需要从多个文件中删除一段代码。我在核心项目中遇到瑞典语字符问题,因此我需要安装 System.Text.CodePagesEncodingProvider nuget 包并使用 System.Text.Encoding.GetEncoding(1252) 而不是 System.Text.Encoding.UTF8。
public static void Main(string[] args)
{
try
{
var dir = @"C:\Test";
//Get all html and htm files
var files = DirSearch(dir);
foreach (var file in files)
{
RmCode(file);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw;
}
}
private static void RmCode(string file)
{
string tempFile = Path.GetTempFileName();
using (var sr = new StreamReader(file, Encoding.UTF8))
using (var sw = new StreamWriter(new FileStream(tempFile, FileMode.Open, FileAccess.ReadWrite), Encoding.UTF8))
{
string line;
var startOfBadCode = "<div>";
var endOfBadCode = "</div>";
var deleteLine = false;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains(startOfBadCode))
{
deleteLine = true;
}
if (!deleteLine)
{
sw.WriteLine(line);
}
if (line.Contains(endOfBadCode))
{
deleteLine = false;
}
}
}
File.Delete(file);
File.Move(tempFile, file);
}
private static List<String> DirSearch(string sDir)
{
List<String> files = new List<String>();
try
{
foreach (string f in Directory.GetFiles(sDir))
{
files.Add(f);
}
foreach (string d in Directory.GetDirectories(sDir))
{
files.AddRange(DirSearch(d));
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
return files.Where(s => s.EndsWith(".htm") || s.EndsWith(".html")).ToList();
}