Загрузка изображения из Inte rnet с указанием c DateTime в URL - PullRequest
2 голосов
/ 04 марта 2020

Я пытаюсь разработать приложение, которое будет извлекать файл с веб-сервера, используя сгенерированный путь URL.
Новый файл на веб-сервере создается каждую секунду, и я пытаюсь получить доступ к этому файлу и отобразить это в PictureBox (старые файлы не удаляются).
Я столкнулся с некоторыми проблемами, сервер возвращает ошибку 404, но я не могу понять, почему.
Приложение, похоже, не может чтобы загрузить файл, используя сгенерированный источник изображения Url, но когда я захожу на сгенерированную ссылку в веб-браузере (например, Chrome, Inte rnet Explorer), он работает просто отлично.
Я также столкнулся с некоторыми проблемами способ неправильного форматирования URL.

Попробуйте 1: Я попытался загрузить файл, используя строку, выведенную моим генератором URl. URl должен быть в форме даты: yyyyMMdd/yyyyMMddHHmmss по стандартному времени Токио. Генерация этой части работала нормально и никаких проблем не возникало. Это мой код:

' Convert the time to Tokyo Standard Time
Dim japanTime = System.TimeZoneInfo.ConvertTime(Now, TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time")) 

'Convert date to url that can be used in the Monitor url
Dim jTime_url As String = Convert.ToDateTime(japanTime.ToString()).ToString("yyyyMMdd/yyyyMMddHHmmss") 

'BYTE ARRAY HOLDS THE DATA
Try
    PictureBox1.Load("www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/" + jTime_url + ".jma_s.gif")
    Console.WriteLine("http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/" + jTime_url + ".jma_s.gif")
Catch ex As Exception
    Console.WriteLine(ex.Message)
End Try

Проблема, с которой я столкнулся, заключалась в том, что я, возможно, слишком быстро запросил последний файл, поэтому веб-сервер всегда будет сообщать "404 file not found".

Попробуйте 2: Я попытался отложить захват файла на 4 секунды. Это работало, большую часть времени. Проблемы заключались в том, что файл, полученный с веб-сервера, работал только большую часть времени из-за того факта, что как только «второе» значение достигнет 0, полученная строка будет -4 вместо 56.
Вторая проблема заключалась в том, что весь код иногда не работал случайным образом, просто возвращая ошибку "404 file not found".
Я попытался вывести URL-адреса на консоль и просмотрел эти онлайн-изображения в своем веб-браузере, и они работали просто хорошо каждый раз. Третья проблема заключалась в том, что мне нужно было преобразовать «секунды» в 00, 01, 02 et c.

Dim japanTime = System.TimeZoneInfo.ConvertTime(Now, TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time")) 'Convert user computer time to TokyoTime (japan)

'For debugging purposes only (not enabled)
' MessageBox.Show(japanTime.ToString()) 

'FORMAT OUTPUTTED: 1/19/2020 1:47:18 PM

'Needed format: yyyyMMdd/yyyyMMddHHmmss
Dim oldsecond As String = Convert.ToDateTime(japanTime.ToString()).ToString("ss") 'Create the old second to make a delay (source code not right)
' Dim oldminute As String = Convert.ToDateTime(japanTime.ToString()).ToString("mm")

'The -1 Explains the code delay
Dim newsecond As String = oldsecond - 5 

Dim newnewsecond As String
If newsecond = -4 Then
    newnewsecond = "56"
Else
    If newsecond = -3 Then
        newnewsecond = "57"
    Else
        If newsecond = -2 Then
            newnewsecond = "58"
        Else
            If newsecond = -1 Then
                newnewsecond = "59"
            Else
                If newsecond = 0 Then
                    newnewsecond = "00"
                Else
                    newnewsecond = newsecond
                End If
            End If
        End If
    End If
End If
Label4.Text = newnewsecond

Dim jTime_url As String = Convert.ToDateTime(japanTime.ToString()).ToString("yyyyMMdd/yyyyMMddHHmm" & newnewsecond) 'Convert date to url that can be used in the Monitor url
Dim MyWebClient As New System.Net.WebClient

Try
    PictureBox1.Load("www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/" + jTime_url + ".jma_s.gif")
    Console.WriteLine("http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/" + jTime_url + ".jma_s.gif")
  Catch ex as Exception
    Console.Writeline(ex.message)
End Try

Здесь я пытаюсь добиться того, чтобы я мог отображать этот URL-адрес источника изображения, используя самую последнюю информацию о дате, заменяя yyyyMMdd/yyyyMMddHHmmss и отображая ее в PictureBox.

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

http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/yyyyMMdd/yyyyMMddHHmmss.jma_s.gif

Пример источника изображения URL, который вы можете посмотреть:
http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/20200304/20200304081359.jma_s.gif

1 Ответ

3 голосов
/ 04 марта 2020

Я изменил метод преобразования DateTime, используя TimeZoneInfo.ConvertTimeBySystemTimeZoneId , передав мои Local TimeZone.Id и "Tokyo Standard Time" в качестве параметров, чтобы сгенерировать DateTimeOffset это представляет текущий Токио DateTime.

Используя таймер, вычитая 4 секунды из вычисленного DateTimeOffset (DateTimeOffset.AddSeconds(-4)), изображения загружаются правильно.

► Обратите внимание, что системные часы должны быть синхронизированы с NTP-сервером . 4 секунд - это относительно слабая пропасть, но несинхронизированные часы, конечно, все равно скомпрометируют результат.

РЕДАКТИРОВАТЬ :
Изменено System.Windows.Forms.Timer на System.Timers.Timer, поскольку здесь требуется больше времени для загрузки изображения.
Использование BeginInvoke() для установки PictureBox.Image, которое почти ничего не требует, препятствует тому, чтобы пользовательский интерфейс заикался при перемещении формы.

Private tokyoTimer As System.Timers.Timer = Nothing
Private tokyoClient As WebClient

Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
    tokyoTimer = New System.Timers.Timer() With {.Interval = 1000}
    tokyoClient = New WebClient()
    AddHandler tokyoTimer.Elapsed,
        Sub()
            Dim TokyoOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(Date.Now, TimeZoneInfo.Local.Id, "Tokyo Standard Time")
            Dim currentImage As String = TokyoOffset.AddSeconds(-4).ToString("yyyyMMdd/yyyyMMddHHmmss") & ".jma_s.gif"
            Try
                Dim data = tokyoClient.DownloadData(New Uri($"http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/{currentImage}"))
                BeginInvoke(New MethodInvoker(
                    Sub()
                        PictureBox1.Image?.Dispose()
                        PictureBox1.Image = Image.FromStream(New MemoryStream(data))
                    End Sub))
            Catch ex As Exception
                ' The exception hadling can be quite extensive here, since many factor can cause it: 
                ' No server response, no Internet connection, internal server (500+) faults etc.
                Console.WriteLine(ex.Message)
            End Try
        End Sub
    tokyoTimer.Enabled = True
End Sub

Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
    tokyoTimer.Enabled = False
    tokyoTimer.Dispose()
    tokyoClient?.Dispose()
End Sub

Tokyo Images



Асинхронная версия одной и той же процедуры, все содержатся в объекте класса .
Класс TokyoImagesDownloader предоставляет два открытых метода c:

StartDownload() ожидает в качестве аргументов:
1. Элемент управления PicureBox, используемый для отображения загруженного images
2. Интервал в секундах между загрузками.
3. Значение задержки в секундах для вычитания из текущего Токийского местного времени, чтобы предотвратить возврат сервером 404 - Not found, поскольку запрашиваемое изображение еще не готов.

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

StopDownload() можно вызвать в любое время, чтобы остановить загрузку изображений.

С:

StartDownload(PictureBox1, 1, 8)

класс проинструктирован показывать изображения в PictureBox1, загружать изображения каждую секунду и задерживать текущее время Токио на 8 секунд.

Dim imageDonwloder As TokyoImagesDownloader = Nothing

Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
    imageDonwloder = New TokyoImagesDownloader()
    imageDonwloder.StartDownload(PictureBox1, 1, 8)
End Sub

Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
    imageDonwloder.StopDownload()
End Sub

Imports System.IO
Imports System.Net

Public Class TokyoImagesDownloader

    Private tokyoClient As WebClient
    Private cts As CancellationTokenSource = Nothing

    Public Sub StartDownload(canvas As PictureBox, intervalSeconds As Integer, serverTimeDelaySeconds As Integer)
        cts = New CancellationTokenSource()
        tokyoClient = New WebClient()
        Task.Run(Function() DownloadAsync(canvas, intervalSeconds, serverTimeDelaySeconds))
    End Sub

    Private Async Function DownloadAsync(canvas As PictureBox, intervalSeconds As Integer, serverTimeDelaySeconds As Integer) As Task
        Dim downloadTimeWatch As Stopwatch = New Stopwatch()
        downloadTimeWatch.Start()
        Do
            If cts.IsCancellationRequested Then Return
            Dim TokyoOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(Date.Now, TimeZoneInfo.Local.Id, "Tokyo Standard Time")
            Dim currentImage As String = TokyoOffset.AddSeconds(-serverTimeDelaySeconds).ToString("yyyyMMdd/yyyyMMddHHmmss")
            Dim url = New Uri($"http://www.kmoni.bosai.go.jp/data/map_img/RealTimeImg/jma_s/{currentImage}.jma_s.gif")
            Try
                Dim data = Await tokyoClient.DownloadDataTaskAsync(url)
                canvas.BeginInvoke(New MethodInvoker(
                    Sub()
                        canvas.Image?.Dispose()
                        canvas.Image = Image.FromStream(New MemoryStream(data))
                    End Sub))
                Await Task.Delay((intervalSeconds * 1000) - CInt(downloadTimeWatch.ElapsedMilliseconds))
                downloadTimeWatch.Restart()
            Catch wEx As WebException
                Console.WriteLine(wEx.Message)
            End Try
        Loop
    End Function

    Public Sub StopDownload()
        cts.Cancel()
        tokyoClient?.CancelAsync()
        tokyoClient?.Dispose()
        cts?.Dispose()
    End Sub
End Class
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...