VB.Net - opening a file which may be local or remote (via http)
Question
I wonder if someone can help me;
In PHP you can use fopen(Path) to read from a file. The Path can be either a local file (in the usual formats /etc/file or c:\file.txt) OR it can be a URL in which case PHP will open a http connection and read from the remote location
I'd like to achieve the same in VB.Net. I'm not aware of any framework function which will achieve this.
I'm currently pattern matching the path against a Regex for a valid URL - If I get a match, I open the file using a httpwebrequest otherwise I try to use the local file system.
This is all a little bit hacky - I'm hoping to find a better way to implement this.
Any advice or suggestions would be appreciated.
Private Function RetrieveBGImage() As Image
Dim Ret As Image
If Not (IsURL(_BackgroundImage) Or IsLocalFile(_BackgroundImage)) Then
Throw New Exception(String.Format("Unable to load from uri ""{0}""", _BackgroundImage))
End If
If IsURL(_BackgroundImage) Then
Dim Response As Net.HttpWebResponse = Nothing
Try
Dim Request As Net.HttpWebRequest = DirectCast(Net.HttpWebRequest.Create(_BackgroundImage), Net.HttpWebRequest)
Response = DirectCast(Request.GetResponse, Net.HttpWebResponse)
Ret = Image.FromStream(Response.GetResponseStream())
Catch ex As Exception
Throw New Exception(String.Format("Unable to load uri: ""{0}"" using HTTPWebRequest. {1}", _BackgroundImage, ex.Message), ex)
Finally
If Response IsNot Nothing Then
Response.Close()
End If
Response = Nothing
End Try
Else
Try
Ret = Image.FromFile(_BackgroundImage)
Catch ex As Exception
Throw New Exception(String.Format("Unable to load uri ""{0}"" using local file system. {1}", _BackgroundImage, ex.Message), ex)
End Try
End If
Return Ret
End Function
Private Function IsURL(ByVal Path As String) As Boolean
Dim RegexObj As New Regex("^(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w\d{1-3}]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|edu|co\.uk|ac\.uk|it|fr|tv|museum|asia|local|travel|[a-z]{2})?)(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?$")
Dim MatchObj As Match = RegexObj.Match(Path)
Return MatchObj.Success
End Function
Private Function IsLocalFile(ByVal Path As String) As Boolean
Dim Ret As Boolean = False
Try
Dim FInfo As New FileInfo(_BackgroundImage)
Ret = FInfo.Exists
Catch handledex As ArgumentException
'Ignore invalid path errors
Catch ex As Exception
Throw New Exception(String.Format("Unable to load uri ""{0}"" using local file system. {1}", Path, ex.Message), ex)
End Try
Return Ret
End Function
NB: I'm aware that the logic above is inefficient and actually ends up calling IsURL() more than it has to - I'm intending to tidy it up if I can't find a more elegant solution.
Thanks in advance for any help
Solution
Another Option: It looks like the base class webrequest will work for local and http files. It was hiding under our nose the whole time. Let me know if this does not meet your needs in any way.
Private Function RetrieveBGImage() As Image
Dim Ret As Image
Dim Response As Net.WebResponse = Nothing
Try
Dim Request As Net.WebRequest = Net.WebRequest.Create(_BackgroundImage)
Response = Request.GetResponse
Ret = Image.FromStream(Response.GetResponseStream())
Catch ex As Exception
Throw New Exception(String.Format("Unable to load file", _BackgroundImage, ex.Message), ex)
Finally
If Response IsNot Nothing Then
Response.Close()
End If
Response = Nothing
End Try
Return Ret
End Function
OTHER TIPS
I blieve you can use My.Computer.Network.DownloadFile It appears to do both. It does not generate a stream but if you have a temporary directory to put the file then DownloadFile can do all the heavy listing and you could the open the temporary file from a known location. I ran this quick test to make sure and it worked from a URL and a file.
My.Computer.Network.DownloadFile("c:/test1.txt", "C:/test2.txt")
My.Computer.Network.DownloadFile("http://google.com", "C:/test3.txt")
Let me know if this does not meet your needs in any way.