Чтение HttpPostedFile перед сохранением сохраняет пустой файл в ASP.NET MVC - PullRequest
7 голосов
/ 16 декабря 2010

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

Вот мой метод действия

[HttpPost]
public ActionResult Import(HttpPostedFileBase file)
{
    // Check parse went ok
    using (var fileStream = file.InputStream)
    {
        if (!MemberFileParsingService.CheckFileWillParse(fileStream))
        {
            ViewBag.Message = "There was a problem with the file";
            return View();
        }
    }

    // Save file so we can work on it in next action
    file.SaveAs(Server.MapPath(fileName));

    return RedirectToAction("ImportMatch", new { club = ActiveClub.Url });
}

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

public static bool CheckFileWillParse(Stream fileStream)
{
    try
    {
        using (var reader = new StreamReader(fileStream))
        {
            using (CsvReader csv = new CsvReader(reader, false))
            {
                while (csv.ReadNextRecord()) { }
            }
        }
    }
    catch(Exception)
    {
        return false;
    }
    return true;
}

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

Так как я могу сбросить поток или это просто красная сельдь?

Обновление: Обнаружено, что длина потока сбрасывается в ноль после прохождения CheckFileWillParse, поэтому похоже, что сброс потока - это просто красная сельдь, и поток фактически как-то блокируется.

Ответы [ 4 ]

5 голосов
/ 16 декабря 2010

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

Для этого можно использовать функцию Seek или свойство Position.(установите его в 0).Однако не все типы потоков поддерживают это.

Если тип потока не поддерживает его, вам может понадобиться сначала записать файл на диск, а затем запустить тест для него.

3 голосов
/ 26 мая 2013

Из-за оператора using будет вызван метод Dispose() для вашего объекта StreamReader.Это фактически закроет базовый Stream объект.Следовательно, почему поток имеет нулевую длину.

Опция 1:

Один из вариантов - не удалять экземпляр StreamReader, удаляя оператор using.Вам нужно будет вручную удалить поток позже (но, возможно, CsvReader сделает это за вас), вызвав его метод Dispose().

Сборщик мусора очистит объект StreamReader и не будетзакройте базовый поток.

Опция 2:

Вы можете использовать следующий конструктор при создании экземпляра StreamReader:

public StreamWriter(
    Stream stream,
    Encoding encoding,
    int bufferSize,
    bool leaveOpen
)

Установка параметра leaveOpen на true гарантирует, что поток не будет закрыт.

3 голосов
/ 16 декабря 2010

Рассматривали ли вы создание копии потока для анализа, используя Stream.CopyTo()?

2 голосов
/ 13 апреля 2012

Поскольку метод утилизации StreamReader также удалит ваш базовый поток.

MemoryStream ms = new MemoryStream();
myStream.CopyTo(ms);
myStream.Position = ms.Position = 0; // !Don't forget this!
//And then read your 'ms' here
...