Вопрос
Поддерживает ли File.AppendAllText
коллизии от нескольких авторов?
Исследование
Я заметил, что документация MSDN на самом деле не обеспечивает позицию в любом случае, поэтому я решил, что буду отражать код и просто посмотреть, что он делает. Ниже вызывается метод из File.AppendAllText
:
private static void InternalAppendAllText(string path, string contents, Encoding encoding)
{
using (StreamWriter streamWriter = new StreamWriter(path, true, encoding))
{
streamWriter.Write(contents);
}
}
и, как вы видите, он просто использует StreamWriter
. Итак, если мы углубимся в это, в частности конструктор, который он использует, мы обнаружим, что он в конечном итоге вызывает этот конструктор:
internal StreamWriter(string path, bool append, Encoding encoding, int bufferSize, bool checkHost) : base(null)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
if (encoding == null)
{
throw new ArgumentNullException("encoding");
}
if (path.Length == 0)
{
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
}
Stream streamArg = StreamWriter.CreateFile(path, append, checkHost);
this.Init(streamArg, encoding, bufferSize, false);
}
со следующими значениями:
path: the path to the file
append: the text to append
encoding: UTF8NoBOM
bufferSize: 1024
checkHost: true
и далее мы обнаруживаем, что реализация base(null)
на самом деле ничего не делает, кроме как установить InternalFormatProvider
на null
. Итак, если мы продолжаем копать, мы обнаруживаем, что CreateFile
:
private static Stream CreateFile(string path, bool append, bool checkHost)
{
FileMode mode = append ? FileMode.Append : FileMode.Create;
return new FileStream(path, mode, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost);
}
создает FileStream
с этими значениями параметров:
path: the path to the file
mode: FileMode.Append
access: FileAccess.Write
share: FileShare.Read
bufferSize: 4096
options: FileOptions.SequentialScan
msgPath: just the file name of the path provided
bFromProxy: false
useLongPath: false
checkHost: true
Итак, теперь мы наконец-то получаем то, что мы собираемся использовать API Windows, и именно здесь вопрос действительно начинается, потому что FileStream::ctor
вызывает метод с именем Init
. Это довольно длинный метод, но меня действительно интересует одна строка:
this._handle = Win32Native.SafeCreateFile(text3,
dwDesiredAccess,
share,
secAttrs,
mode,
num,
IntPtr.Zero);
который, конечно, вызывает CreateFile
, где значения параметра:
text3: the full path to the file
dwDesiredAccess: 1073741824
share: 1 (FILE_SHARE_READ)
secAttrs: null
mode: 4 (OPEN_ALWAYS)
num: 134217728 | 1048576 (FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_POSIX_SEMANTICS)
Итак, что бы сделать Windows, если бы у меня было два потока, пытающихся получить доступ к этому вызову в одно и то же время для одного и того же пути? Будет ли он открывать файл и буферизовать записи, чтобы оба потребителя могли писать в файл? Или мне нужно использовать объект блокировки и lock
вокруг вызова AppendAllText
?