tags:

views:

384

answers:

2

Hi all,

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

+1  A: 

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.

Bentley Davis
It's excellent and far simpler than my mess. The only slight issue is that I'd prefer to do it without writing to the disk - I'm expecting to process a lot of images and although I could manually clean up the temp files, I won't have need of them s a cache and it adds a requirement for a scheduled cleanup task or similar... Do you know any way I can implement this in-memory?
Basiclife
I figured you would say that. I'll look around.
Bentley Davis
Sorry :s and thanks :)
Basiclife
Worst case: have a look at the code of `My.Computer.Network.DownloadFile` in the Reflector to see what it does internally.
Konrad Rudolph
Great idea. I was looking at it while you were commenting. It calls the base webrequest which is where I got the idea for the next answer.
Bentley Davis
+2  A: 

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
Bentley Davis
That's perfect - thanks very much!
Basiclife