.net - 从 Internet 下载 URL 中具有特定日期时间的图像
问题描述
我正在尝试开发一个应用程序,该应用程序将使用生成的 Url 路径从 Web 服务器获取文件。
每秒都会在 Web 服务器上创建一个新文件,我正在尝试访问该文件并将其显示在 PictureBox 中(旧文件不会被删除)。
我遇到了一些问题,服务器返回404
错误,但我不知道为什么。
该应用程序似乎无法使用生成的图像源 URL 下载文件,但是当我在 Web 浏览器(例如 Chrome、Internet 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 秒。这在大多数情况下都有效。问题是从 Web 服务器获取的文件仅在大部分时间都有效,因为一旦达到“秒”值0
,输出的字符串将-4
不是56
.
第二个问题是整个代码有时不会随机运行,只是返回错误"404 file not found"
。
我尝试将 URL 输出到控制台,并在我的网络浏览器中查看了这些在线图像,它们每次都运行良好。第三个问题是我需要将“秒”转换为输出为00
,01
等02
。
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
我在这里想要实现的是,我希望能够使用最新的日期信息替换 yyyyMMdd/yyyyMMddHHmmss
并在 PictureBox 中显示这个图像源 URL。
我的代码中是否有错误,我可以改进它还是必须以其他方式、形状或形式重新编写它?
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
解决方案
我更改了 DateTime 转换方法,使用TimeZoneInfo.ConvertTimeBySystemTimeZoneId,传递我的Local TimeZone.Id和"Tokyo Standard Time"
作为参数,以生成代表当前东京 DateTime 的 DateTimeOffset 。
使用计时器,从计算的 DateTimeOffset ( DateTimeOffset.AddSeconds(-4)
) 中减去 4 秒,图像被正确加载。
► 请注意,系统时钟必须与NTP 服务器同步。4
秒是一个相对宽松的差距,但不同步的时钟当然会影响结果。
编辑:
更改System.Windows.Forms.Timer
为System.Timers.Timer
,因为这里需要更多时间的是图像下载。
使用BeginInvoke()
设置PictureBox.Image
几乎不需要任何内容,可防止 UI在窗体移动时出现卡顿。
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
同一过程的异步版本,全部包含在一个类对象中。
该类TokyoImagesDownloader
公开了两个公共方法:
▶StartDownload()
期望作为参数:
- PicureBox 控件用于显示下载的图像
- 下载之间的时间间隔(以秒为单位)。
- 一个延迟值,以秒为单位,减去当前的东京当地时间,以防止服务器
404 - Not found
因为请求的图像尚未准备好而返回。
AStopWatch
用于在下载之间同步请求的间隔,考虑到下载和显示图像所需的时间,因此图像本身显示的时钟应反映请求的间隔。
▶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
推荐阅读
- c# - 旋转 UILabel 的拉伸宽度
- python - 根据 MultiIndex DataFrame 中的第一级列删除重复项
- buildkite - 如何在 buildkite 中为存储库/管道级别添加访问控制?
- java - 错误:SqlExceptionHelper:HOUR_OF_DAY:2 -> 3
- ios - Xcode 11 GM Seed 2 在构建工作区/项目时冻结
- ios - 如何激活包月试订阅(自动续费)?
- php - Laravel Gazzel 向同一个 URL 发出多个请求而无需多次登录
- javascript - 无法将主机设置为节点 net.socket 连接
- php - 如何过滤 sql 数组的索引并显示它们...?
- c# - 修改字符串是否合法?