C # Чтение CSV из URL-адреса и сохранить в базу данных - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь получить данные из csv-файла из веб-службы.Если я вставлю URL в моем браузере, CSV будет загружен и будет выглядеть следующим образом:

    "ID","ProductName","Company"
    "1","Apples","Alfreds futterkiste"
    "2","Oranges","Alfreds futterkiste"
    "3","Bananas","Alfreds futterkiste"
    "4","Salad","Alfreds futterkiste"
     ...next 96 rows

Однако я не хочу сначала загружать CSV-файл, а затем извлекать данные из него впоследствии,Веб-сервис использует разбиение на страницы и возвращает 100 строк (определяется параметром & num с максимальным значением 100).После первого запроса я могу использовать параметр & next-для получения следующих 100 строк на основе идентификатора.Например, url

http://testWebservice123.com/Example.csv?auth=abc&number=100&next=100

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

После небольшого поискаЯ пришел к следующему решению

static void Main(string[] args)
    {


        string startUrl = "http://testWebservice123.com/Example.csv?auth=abc&number=100";
        string url = "";
        string deltaRequestParameter = "";
        string lastLine;
        int numberOfLines = 0;

        do
        {
            url = startUrl + deltaRequestParameter;
            WebClient myWebClient = new WebClient();

            using (Stream myStream = myWebClient.OpenRead(url))
            {

                using (StreamReader sr = new StreamReader(myStream))
                {
                    numberOfLines = 0;
                    while (!sr.EndOfStream)
                    {
                        var row = sr.ReadLine();
                        var values = row.Split(',');

                        //do whatever with the rows by now - i.e. write to console
                        Console.WriteLine(values[0] + " " + values[1]); 

                        lastLine = values[0].Replace("\"", ""); //last line in the loop - get the last ID.
                        numberOfLines++;
                        deltaRequestParameter = "&next=" + lastLine;
                    }

                }

            }
        } while (numberOfLines == 101); //since the header is returned each time the number of rows will be 101 until we get to the last request


    }

, но я не уверен, является ли это «современным» способом сделать это, или есть лучший способ (проще / проще)?Другими словами, я не уверен, правильно ли использовать WebClient и StreamReader?

В этой теме: как прочитать файл csv из URL-адреса?

Упоминается WebClient.DownloadString, а также WebRequest.Но если я хочу записать в базу данных без сохранения csv в hdd, что является лучшим вариантом?

Furhtermore - будет ли принятый мной подход сохранять данные во временном хранилище за кулисами или все данные будут прочитаныв память, а затем утилизируется, когда цикл завершается?Я прочитал следующую документацию, но не могу выяснить, что он делает за кулисами: StreamReader: https://docs.microsoft.com/en-us/dotnet/api/system.io.streamreader?view=netframework-4.7.2

Stream: https://docs.microsoft.com/en-us/dotnet/api/system.io.stream?view=netframework-4.7.2

Редактировать: Я думаю, я мог бы такжеиспользовать следующий "TextFieldParser" ... но мои вопросы на самом деле все тот же:

(с использованием сборки Microsoft.VisualBasic)

    using (Stream myStream = myWebClient.OpenRead(url))
                {

                    using (TextFieldParser parser = new TextFieldParser(myStream))
                    {
                        numberOfLines = 0;

                        parser.TrimWhiteSpace = true; // if you want
                        parser.Delimiters = new[] { "," };
                        parser.HasFieldsEnclosedInQuotes = true;
                        while (!parser.EndOfData)
                        {
                            string[] line = parser.ReadFields();
                            Console.WriteLine(line[0].ToString() + " " + line[1].ToString());

                            numberOfLines++;

                            deltaRequestParameter = "&next=" + line[0].ToString();


                        }


                    }

                }

1 Ответ

0 голосов
/ 31 января 2019

Класс HttpClient в System.Web.Http доступен с версии .Net 4.5.Вы должны работать с асинхронным кодом, но это неплохая идея, если вы работаете с Интернетом.

В качестве примера данных я буду использовать список"todo" jsonplaceholder.Он предоставляет данные JSON, а не данные CSV, но он дает достаточно простую структуру, которая может служить нашей цели в приведенном ниже примере.

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

async void DownloadPagesAsync() {

    for (var i = 1; i < 3; i++) {

        var pageToGet = $"https://jsonplaceholder.typicode.com/todos/{i}";

        using (var client = new HttpClient())
        using (HttpResponseMessage response = await client.GetAsync(pageToGet))
        using (HttpContent content = response.Content)
        using (var stream = (MemoryStream) await content.ReadAsStreamAsync()) 
        using (var sr = new StreamReader(stream))
        while (!sr.EndOfStream) {

            var row = 
                sr.ReadLine()
                .Replace(@"""", "")
                .Replace(",", "");

            if (row.IndexOf(":") == -1)
                continue;

            var values = row.Split(':');
            Console.WriteLine($"{values[0]}, {values[1]}");

        }

    }

}

Вот как вы бы вызывали функцию, например, как в методе Main ():

Task t = new Task(DownloadPagesAsync);
t.Start();

Новая задача, которая здесь выполняется, - это "действие"или, или другими словами, функция, которая возвращает void, в качестве параметра.Затем вы начинаете задание.Будьте осторожны, он асинхронный, поэтому любой код, который вы имеете после t.Start (), может очень хорошо выполнить до того, как ваша задача завершится.

Что касается вашего вопроса относительно того, читает ли поток «в памяти» или нет,запуск GetType () для «потока» в коде привел к типу «MemoryStream», хотя он, кажется, распознается как объект «Stream» только во время компиляции.MemoryStream определенно находится в памяти.Я не совсем уверен, сохранит ли какой-нибудь другой вид потоковых объектов временные файлы за кулисами, но я склоняюсь не к этому.

Но, хотя вы и заслуживаете похвалы, внутренняя работа класса, как правило, не требуется для вашего беспокойства об утилизации.Для любого класса просто посмотрите, реализует ли он IDisposable.Если это так, вставьте оператор «using», как вы это делали в своем коде.Когда программа завершается, как и ожидалось, или из-за ошибки, программа выполнит правильное удаление после того, как управление выйдет из блока «using».

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

Кроме того, кое-что, что нужно знать о WebClient, это то, что он может быть простым, но ограничивающим.Если вы столкнетесь с проблемами, вам нужно будет обратиться к классу HttpWebRequest, который является классом «более низкого уровня», который дает вам более широкий доступ к основным моментам (таким как работа с файлами cookie).

...