Различное поведение при потоковой передаче и сохранении файла с ftp-сервера с использованием FtpWebRequest на рабочей машине ASP.Net - PullRequest
1 голос
/ 18 мая 2011

Может быть, есть очень простой ответ на этот вопрос, но я действительно застрял на этом.

Я написал некоторый код, который выбирает довольно большой (4 ГБ +) XML-файл через ftp, читает его как строку и разбивает документ на более мелкие части. Наконец, файлы меньшего размера записываются на диск.

Все отлично работает на моей машине разработчика, но при запуске в работу сценарий неожиданно завершает работу после прочтения только одной десятой части файла. Никаких исключений не выбрасывается. Каждая строка кода выполняется так, как ожидается. Это просто заканчивается, прежде чем пройти через весь файл. Это заставляет меня думать, что нужно изменить некоторые настройки IIS или web.config.

Код выполняется внутри Umbraco CMS как пользовательский элемент управления. Сервер - это машина Windows 2008 с IIS.

Есть идеи? Это код:

FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
    request.Credentials = new NetworkCredential("anonymous", "x@y.z");
    request.Method = WebRequestMethods.Ftp.DownloadFile;
    request.Timeout = -1;
    request.KeepAlive = true;
    request.UsePassive = true;
    request.UseBinary = true;
    using (response = (FtpWebResponse)request.GetResponse())
    using (responseStream = response.GetResponseStream())
    using (StreamReader sr = new StreamReader(responseStream))
    {
      ReadStreamIntoNewRecord(fileName, sr, ref progress, ref result);
    }

Функция ReadStreamIntoNewRecord выглядит следующим образом:

private void ReadStreamIntoNewRecord(string fileName, StreamReader sr, int NumberOfRecordsPerBatch)
{
    string line = "";
    string record = "";
    int i = 0;  
    XDocument xdoc = new XDocument(new XElement("collection"));
    while (sr.Peek() >= 0)
    {
        line = sr.ReadLine();
        if (line.Contains("</record>"))
        {
            xdoc.Element("collection").Add(MakeRecordFromString(record + line));
            record = "";
            i++;
            if (i % NumberOfRecordsPerBatch == 0)
            {
                SaveRecordToFile(fileName, xdoc);
                xdoc = new XDocument(new XElement("collection"));
            }
        }
        else
        {
            record = record + line;
        }

    }
    SaveRecordToFile(fileName, xdoc);            
}

1 Ответ

2 голосов
/ 19 мая 2011

Ничего себе, загрузка файла 4 ГБ в строку в памяти - ужасная идея.Если это 4 ГБ на диске как UTF-8, тогда это будет 8 ГБ в памяти, так как все строки .NE имеют UTF-16 в памяти.К счастью, вы на самом деле этого не делаете, вы просто сказали, что были в описании.

Я полагаю, вам следует немного изменить цикл while.Как написано, это может быть обнаружение неправильного завершения потока, когда поступает действительно больше данных. Используйте это вместо этого:

while ((line = sr.ReadLine()) != null)
{
    ...
}

Кроме того, вам было бы гораздо лучше использовать простой StreamWriter илиXmlTextWriter чтобы сохранить файл вместо XDocument.XDocument хранит весь файл в памяти и разработан для облегчения прохождения через Linq-to-Xml.Вы не используете его и можете извлечь выгоду из гораздо более легкой весовой категории.

...