Как избежать чрезмерного ввода-вывода сетевых файлов при добавлении большого файла с помощью .NET? - PullRequest
7 голосов
/ 30 июня 2010

У меня есть программа, которая открывает большой двоичный файл, добавляет к нему небольшой объем данных и закрывает файл.

FileStream fs = File.Open( "\\\\s1\\temp\\test.tmp", FileMode.Append, FileAccess.Write, FileShare.None );
fs.Write( data, 0, data.Length );
fs.Close();

Если test.tmp равен 5 МБ до запуска этой программы, а массив данных - 100 байтов, эта программа приведет к передаче через сеть более 5 МБ данных.Я ожидал бы, что данные, уже находящиеся в файле, не будут передаваться по сети, поскольку я не читаю и не пишу.Есть ли способ избежать такого поведения?Это мучительно медленно добавляет к очень большим файлам.

Ответы [ 7 ]

2 голосов
/ 30 июня 2010

0xA3 предоставил ответ в комментарии выше. Низкая производительность была вызвана проверкой на вирусы при доступе. Каждый раз, когда моя программа открывала файл, антивирусный сканер считывал все содержимое файла, чтобы проверить его на наличие вирусов, даже если моя программа не прочитала какой-либо существующий контент. Отключение проверки на вирусы при доступе устраняет чрезмерный сетевой ввод-вывод и низкую производительность.

Спасибо всем за ваши предложения.

1 голос
/ 30 июня 2010

Я нашел это на MSDN (CreateFile вызывается внутри):

Когда приложение создает файл по сети, лучше использовать GENERIC_READ | GENERIC_WRITE для dwDesiredAccess, чем использовать только GENERIC_WRITE. Результирующий код быстрее, потому что перенаправитель может использовать менеджер кэша и отправлять меньше SMB с большим количеством данных. Эта комбинация также позволяет избежать проблемы, когда запись в файл по сети может иногда возвращать ERROR_ACCESS_DENIED.

Используя Reflector, FileAccess отображается на dwDesiredAccess, поэтому, похоже, рекомендуется использовать FileAccess.ReadWrite вместо FileAccess.Write.

Понятия не имею, поможет ли это:)

0 голосов
/ 30 июня 2010

Запишите данные в отдельные файлы, затем присоедините их (сделайте это на хост-компьютере, если это возможно) только при необходимости.

0 голосов
/ 30 июня 2010

Объект File в .NET имеет довольно много статических методов для обработки этого типа вещей.Я бы предложил попробовать:

File file = File.AppendAllText("FilePath", "What to append", Encoding.UTF8);

Когда вы отражаете этот метод, оказывается, что он использует:

  using (StreamWriter writer = new StreamWriter(path, true, encoding))
{
    writer.Write(contents);
}

Этот метод StreamWriter должен позволить вам просто добавить что-то в конец (впо крайней мере, это метод, который я видел, использовался во всех случаях регистрации, с которыми я сталкивался до сих пор).

0 голосов
/ 30 июня 2010

Если у вас есть доступ к системе или, возможно, дружественный администратор для машины, на которой фактически размещен файл, вы можете создать небольшую программу-слушатель, которая находится на другом конце.

Вы вызываете ее, передавая только данныебыть записанным, и он выполняет запись локально, избегая дополнительного сетевого трафика.

0 голосов
/ 30 июня 2010

Я немного погуглил и больше думал о том, как быстро читать чрезмерно большие файлы, и нашел эту ссылку http://www.4guysfromrolla.com/webtech/010401-1.shtml

Самой интересной частью была бы часть о байт-чтении: помимо наиболее часто используемыхВ методах ReadAll и ReadLine объект TextStream также поддерживает метод Read (n), где n - количество байтов в рассматриваемом файле / текстовом потоке.Создавая дополнительный объект (файловый объект), мы можем получить размер файла, который нужно прочитать, а затем использовать метод Read (n) для просмотра нашего файла.Как оказалось, метод «чтения байтов» чрезвычайно быстр для сравнения:

const ForReading = 1
const TristateFalse = 0
dim strSearchThis
dim objFS
dim objFile
dim objTS
set objFS = Server.CreateObject("Scripting.FileSystemObject")
set objFile = objFS.GetFile(Server.MapPath("myfile.txt"))
set objTS = objFile.OpenAsTextStream(ForReading, TristateFalse)

strSearchThis = objTS.Read(objFile.Size)

if instr(strSearchThis, "keyword") > 0 then
Response.Write "Found it!"
end if

Этот метод может быть использован вами для перехода к концу файла и добавления его вручную вместо загрузкивесь файл в режиме добавления с файловым потоком.

0 голосов
/ 30 июня 2010

Вы можете кэшировать свои данные в локальный буфер и периодически (гораздо реже, чем сейчас) добавлять к большому файлу. Это сэкономило бы кучу сетевых передач, но ... Это также увеличило бы риск потери этого кэша (и ваших данных) в случае сбоя вашего приложения.

Ведение журнала (если оно есть) этого типа часто хранится в БД. Использование достойной СУБД позволит вам размещать эти 100 байтов данных очень часто с минимальными издержками. Предостережение в отношении обслуживания СУБД.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...