追加到新行不会去新行
Appending to new line will not go to new line
我正在尝试将文本框中的文本附加到文本文件中的新行,并将 运行 放入问题中。假设文本文件中已经有内容,看起来像这样
something
Something
Something<---- Cursor ends here
并且光标在箭头指向的位置结束(在最后一个 'something' 上的 g 之后。如果我尝试使用
File.AppendAllLines(@"Location", new[]{tb.Text});
或
File.AppendAllText(@"Location", tb.Text + Environment.NewLine);
他们会将文本放在光标所在的位置,而不是文本文件中最后一项下的新行。如果光标位于新的一行开始,它会起作用,但一旦它在单词的末尾结束,一切都会在同一行上。
有什么我想念的吗?使用 streamwriter 或其他一些方法可以解决这个问题吗?
如果您将 Environment.NewLine
放在文本前面,它应该会为您提供所需的结果:
File.AppendAllText(@"Location", Environment.NewLine + tb.Text);
这正是您要执行的操作。它将您拥有的文本附加到现有文件中。如果那个文件是'wrong',作者也没办法。
如果文件完全在您的控制之下,您可以确保行尾始终写入文件。否则,您可以读取每一行,将您的添加到其中,然后写回整个文件。这显然对大文件不利:
File.WriteAllLines( @"Location"
, File.ReadAllLines(@"Location")
.Concat(new string[] { text })
);
它符合您的预期。你的文本没有用换行符初始化,所以它被附加在前一个文本结束点之后,为了解决你的问题,你可以在写入文件之前打开文件并尝试读取最后一个字节。
bool addNewLine = true;
using (FileStream fs = new FileStream(@"location", FileMode.Open))
using (BinaryReader rd = new BinaryReader(fs))
{
fs.Position = fs.Length - 1;
int last = rd.Read();
// The last byte is 10 if there is a LineFeed
if (last == 10)
addNewLine = false;
}
string allLines = (addNewLine ? Environment.NewLine + tb.Text : tb.Text);
File.AppendAllLines(@"Location", new[]{allLines});
如您所见,这有点复杂,但这避免了读取内存中的所有文件。
实际上,正如其他答案所指出的那样。这是设计使然。 File.AppendAllLines 在文件末尾追加文本。它不会在附加文本之前添加换行符。为此,您必须以某种方式读取文件并确定最后一个字符是否为换行符。有多种方法可以做到这一点。
最简单的方法是读取所有行并检查最后一行是否为空。如果没有,只需在将字符串传递给 File.AppendAllLines.
之前在字符串前加一个换行符
但是,如果处理大文件,或者如果您不想多次打开文件 - 类似于以下方法将执行此操作,同时仍然只打开文件一次。
public void AppendAllLinesAtNewLine(string path, IEnumerable<string> content)
{
// No file, just append as usual.
if (!File.Exists(path))
{
File.AppendAllLines(path, content);
return;
}
using (var stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite))
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
// Determines if there is a new line at the end of the file. If not, one is appended.
long readPosition = stream.Length == 0 ? 0 : -1;
stream.Seek(readPosition, SeekOrigin.End);
string end = reader.ReadToEnd();
if (end.Length != 0 && !end.Equals("\n", StringComparison.Ordinal))
{
writer.Write(Environment.NewLine);
}
// Simple write all lines.
foreach (var line in content)
{
writer.WriteLine(line);
}
}
}
注:long readPosition = s.Length == 0 ? 0:-1;用于处理空文件。
谢谢大家的建议,这就是我决定要做的
FileStream stream = new FileStream("location", FileMode.Open, FileAccess.Read);
char actual = '[=10=]';
if(stream.Length != 0)
{
stream.Seek(-1, SeekOrigin.End);
var lastChar = (byte)stream.ReadByte();
actual = (char)lastChar;
}
stream.Close();
try {
if(addCompT.Text != "")
{
if (actual == '\n' || actual == '[=10=]')
File.AppendAllText("location", addCompT.Text + Environment.NewLine);
else
File.AppendAllText("location", Environment.NewLine + addCompT.Text + Environment.NewLine);
addCompT.Text = "";
}
}
catch(System.UnauthorizedAccessException)
{
MessageBox.Show("Please Run Program As Administrator!");
}
感谢大家的帮助!
我正在尝试将文本框中的文本附加到文本文件中的新行,并将 运行 放入问题中。假设文本文件中已经有内容,看起来像这样
something
Something
Something<---- Cursor ends here
并且光标在箭头指向的位置结束(在最后一个 'something' 上的 g 之后。如果我尝试使用
File.AppendAllLines(@"Location", new[]{tb.Text});
或
File.AppendAllText(@"Location", tb.Text + Environment.NewLine);
他们会将文本放在光标所在的位置,而不是文本文件中最后一项下的新行。如果光标位于新的一行开始,它会起作用,但一旦它在单词的末尾结束,一切都会在同一行上。
有什么我想念的吗?使用 streamwriter 或其他一些方法可以解决这个问题吗?
如果您将 Environment.NewLine
放在文本前面,它应该会为您提供所需的结果:
File.AppendAllText(@"Location", Environment.NewLine + tb.Text);
这正是您要执行的操作。它将您拥有的文本附加到现有文件中。如果那个文件是'wrong',作者也没办法。
如果文件完全在您的控制之下,您可以确保行尾始终写入文件。否则,您可以读取每一行,将您的添加到其中,然后写回整个文件。这显然对大文件不利:
File.WriteAllLines( @"Location"
, File.ReadAllLines(@"Location")
.Concat(new string[] { text })
);
它符合您的预期。你的文本没有用换行符初始化,所以它被附加在前一个文本结束点之后,为了解决你的问题,你可以在写入文件之前打开文件并尝试读取最后一个字节。
bool addNewLine = true;
using (FileStream fs = new FileStream(@"location", FileMode.Open))
using (BinaryReader rd = new BinaryReader(fs))
{
fs.Position = fs.Length - 1;
int last = rd.Read();
// The last byte is 10 if there is a LineFeed
if (last == 10)
addNewLine = false;
}
string allLines = (addNewLine ? Environment.NewLine + tb.Text : tb.Text);
File.AppendAllLines(@"Location", new[]{allLines});
如您所见,这有点复杂,但这避免了读取内存中的所有文件。
实际上,正如其他答案所指出的那样。这是设计使然。 File.AppendAllLines 在文件末尾追加文本。它不会在附加文本之前添加换行符。为此,您必须以某种方式读取文件并确定最后一个字符是否为换行符。有多种方法可以做到这一点。
最简单的方法是读取所有行并检查最后一行是否为空。如果没有,只需在将字符串传递给 File.AppendAllLines.
之前在字符串前加一个换行符但是,如果处理大文件,或者如果您不想多次打开文件 - 类似于以下方法将执行此操作,同时仍然只打开文件一次。
public void AppendAllLinesAtNewLine(string path, IEnumerable<string> content)
{
// No file, just append as usual.
if (!File.Exists(path))
{
File.AppendAllLines(path, content);
return;
}
using (var stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite))
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
// Determines if there is a new line at the end of the file. If not, one is appended.
long readPosition = stream.Length == 0 ? 0 : -1;
stream.Seek(readPosition, SeekOrigin.End);
string end = reader.ReadToEnd();
if (end.Length != 0 && !end.Equals("\n", StringComparison.Ordinal))
{
writer.Write(Environment.NewLine);
}
// Simple write all lines.
foreach (var line in content)
{
writer.WriteLine(line);
}
}
}
注:long readPosition = s.Length == 0 ? 0:-1;用于处理空文件。
谢谢大家的建议,这就是我决定要做的
FileStream stream = new FileStream("location", FileMode.Open, FileAccess.Read);
char actual = '[=10=]';
if(stream.Length != 0)
{
stream.Seek(-1, SeekOrigin.End);
var lastChar = (byte)stream.ReadByte();
actual = (char)lastChar;
}
stream.Close();
try {
if(addCompT.Text != "")
{
if (actual == '\n' || actual == '[=10=]')
File.AppendAllText("location", addCompT.Text + Environment.NewLine);
else
File.AppendAllText("location", Environment.NewLine + addCompT.Text + Environment.NewLine);
addCompT.Text = "";
}
}
catch(System.UnauthorizedAccessException)
{
MessageBox.Show("Please Run Program As Administrator!");
}
感谢大家的帮助!