Анализ данных многочастной формы HTTP с содержимым загрузки файлов с использованием Scala - PullRequest
11 голосов
/ 19 марта 2012

Существует множество multipart / form-data решений по загрузке файлов, но я не смог найти отдельную версию для Scala.

Play2 имеет такую ​​функциональность какчасть фреймворка и Spray также поддерживает составные данные формы.К сожалению, оба они, по-видимому, достаточно интегрированы в остальные наборы инструментов (я могу ошибаться здесь).

Мой сервер был разработан с использованием Finagle (который в настоящее время не поддерживает составные данные форм), и, если возможно, яхотел бы использовать автономное решение lib или «roll my own».

Это типичное сообщение multipart / form-data:

--*****org.apache.cordova.formBoundary
Content-Disposition: form-data; name="value1"

First parameter content
--*****org.apache.cordova.formBoundary
Content-Disposition: form-data; name="value2"

Second parameter content
--*****org.apache.cordova.formBoundary
Content-Disposition: form-data; name="file"; filename="image.jpg"
Content-Type: image/jpeg

$%^&#$%^%#$
--*****org.apache.cordova.formBoundary--

В этом примере *****org.apache.cordova.formBoundary - этограница формы, поэтому многочастная загрузка содержит 2 текстовых параметра и одно изображение (для ясности я объединила данные изображения).

Если кто-то, кто знает Scala лучше меня, может дать мне краткое изложение того, какЯ буду очень признателен за анализ этого содержимого.

Для начала я подумал, что быстро разделю содержимое на три части:

data.split("\\Q--*****org.apache.cordova.formBoundary\\E") foreach println

Но выполнение заметно медленное (обновление -это было из-за времени прогрева).Есть ли более эффективный способ разделения частей?Моя стратегия состоит в том, чтобы разделить контент на части, и разделить части на части.Это дерьмовый подход?Я видел похожие проблемы, решаемые с помощью конечных автоматов?Что такое хороший функциональный подход.Имейте в виду, я пытаюсь научиться правильно подходить к Scala, пытаясь решить проблему.

Обновление:

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

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

Ответы [ 4 ]

1 голос
/ 23 марта 2012

Мне любопытно, насколько медленным является ваш "особенно медленный". Я написал следующую простую маленькую функцию для генерации поддельных сообщений:

def generateFakeMessage(n: Int) = {
  val rand = new scala.util.Random(1L)
  val maxLines = 100
  val maxLength = 100

  (1 to n).map(i =>
    "--*****org.apache.cordova.formBoundary\n" +
    "Content-Disposition: form-data; name=\"value%d\"\n\n".format(i) +
    (0 to rand.nextInt(maxLines)).map(_ =>
      (0 to rand.nextInt(maxLength)).map(_ => rand.nextPrintableChar).mkString
    ).mkString("\n")
  ).mkString("\n") + "\n--*****org.apache.cordova.formBoundary--"
}

Затем я создал достаточно большое сообщение для тестирования:

val data = generateFakeMessage(10000)

В итоге он содержит чуть более полумиллиона строк. Тогда я попробовал ваше регулярное выражение:

data.split("\\Q--*****org.apache.cordova.formBoundary\\E").size

И он возвращается более или менее мгновенно. Вероятно, вы могли бы немного настроить регулярное выражение, и есть более чистые подходы, которые вы могли бы использовать, если ваши данные были Iterable[String] по строкам сообщения, но я не думаю, что вы достигнете лучшей производительности от руки конечный автомат для разбора одного большого String.

0 голосов
/ 08 мая 2012

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

// Take the request and split it into parts
var requestParts = request.content.toString(UTF_8).split("\\Q--*****org.apache.cordova.formBoundary\\E")
// Split the third part at the blank line
val imageParts = requestParts(3).split("\\n\\s*\\n")
// The part above the blank line is the header text
val imageHeader = imageParts(0)
// The part below the blank line is the image body
val imageBodyString = imageParts(1)

Я постараюсь улучшить это позже, но сейчас нужно двигаться вперед.Другой день, другой проект: -o

0 голосов
/ 29 марта 2012

Я думаю, что ваше решение:

data.split("\\Q--*****org.apache.cordova.formBoundary\\E") foreach println

, что по сложности O (n), является лучшим и самым простым, что вы можете получить. Как сказал ранее Трэвис, эта манипуляция не медленная Как всегда с многочастной формой HTTP, вам придется анализировать ее тем или иным способом, и сделать лучше, чтобы O (n) показалось сложным.

Более того, поскольку split предоставляет вам Iterable, оно действительно идеально подходит для любого соответствия, лечения ...

0 голосов
/ 26 марта 2012

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

Кроме того, при необходимости вы можете предоставить более конкретные отображения в Scala для вашей конкретной грамматики. Где Даниил имеет:

def field = (fieldName <~ ":") ~ fieldBody <~ CRLF ^^ {case case ~ body => name -> body}

Вы можете заменить это шаблоном чередования для нескольких полей (contentType|contentDisposition|....) и отобразить каждое из них по отдельности в ваши объекты Scala.

Извините за то, что у вас нет времени написать здесь более подробное решение, но, надеюсь, это укажет вам правильное направление!

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