FileUpload Control Doesn’t Give Full Path….HELP!!!!
I’ve answered this question about five times in the last few days at the forums. It’s getting tedious so I thought I’d make a blog post about it.
Issue:
The FileUpload control has a FileName property. In FireFox (FF) and some other standards compliant browsers, the filename only holds the name of the file. It does NOT hold the full path. In some versions of Internet Explorer (perhaps all versions, but at least up until v7), the FileName property holds a full path. Hence, people see discrepancies among the browsers in terms of the FileName property. A lot of you guys are asking how to get the full path from the file upload control.
What does the FileName property do?
The FileName property holds the name of the uploaded file. In FF, it holds only the file name. In IE7 and earlier (possibly IE8 too – I’ll refer to all of them as IE from here on) it holds THE FULL PATH TO THE FILE ON THE CLIENT’S MACHINE. Read that again, and again, and one more time. It’s the full path of the uploaded file on the client’s machine. NOT THE PATH OF THE UPLOADED FILE ON THE SERVER.
WHOAH…Hang on a minute…the client machine?
Yes. It holds the path to the uploaded file on the machine of the user using the website, not the server. It’s the path you see in the file upload controls text box. It’s the user’s local path to the file. The user may have an M drive with a pics folder. The FileName property will then hold something like M:/pics/pic1.png. The server may not even have an M drive with a pics folder.
That SUCKS!!!! What good is that?
This is a decision made by the creators of IE. It was done to enable easier automation of intranet apps where file operations across the network could be accomplished easier.
Hmmm…Why do them FF guys not support it?
Them FF guys think that letting the server know about the folder structure of a user’s machine is a serious breach of security. For example, if for some reason you had a pic with the path D:\My Racy Photos With X\pic112.jpg (which may be an official photo for whatever reason) and you upload that to the office server, you wouldn’t want your boss (or anyone else) to know that you have a folder called “My Racy Photos With X” on your pc. That’s private info and would be embarrassing if leaked. The worst case scenario would be a few blushes. Now think if you had a folder with some secure info in the name. Even if the contents were secure and not the folder name, you wouldn’t want to make it easier on anyone to get to them. Hence, this can be considered a security flaw.
Ok…err…So where does my uploaded file go to?
The uploaded file is uploaded to a temp location on the server. If you process it, fine. If not, it’s purged (read deleted).
Wait…how do I store the uploaded file then?
Simple. The FileUpload control has a SaveAs(string path) method. You can use that method to save the file to any path using any filename you want. Just make sure asp.net has permissions to write to that path. So, you can do something like this to save the uploaded file to the uploads folder in the root of your website:
fileUpload1.SaveAs(Server.MapPath(“~/uploads/”) + System.IO.Path.GetFilename(fileUpload1.FileName));
[The reason I’m doing a Path.GetFileName is to ensure that even in IE, I only pass the filename and not the entire client side path to the SaveAs method.]
If you wish to provide a different username, you can do that just by changing the parameter. If you wish to append a unique key to each upload, you can use something like Guid.NewGuid().ToString() –or any other technique you want.
Ok smarty pants…saving to the file system is old school. I wanna save it to a database as an array of bytes. If I don’t have the file location, how do I get the array of bytes? How do I use File.ReadAllBytes if I don’t have a path? Huh? Huh?
Glad you asked. The FileUpload control ha a FileBytes property that gives you an array of bytes with all the contents of the file. Just use that.
Now I want to do some processing on the uploaded file. How do I get a Stream without the path?
The FileUpload control has a FileContent property that gives you a stream to the file. You can use it like this:
Stream str = fileUpload1.FileContent;
StreamReader sr = new StreamReader(str);
string contentText = sr.ReadToEnd();
What about the normal <input type=file> file uploads? I don’t like the FileUpload control. Can I get the full filename from that?
The FileUpload control uses the <input type=’file’> tag behind the covers. You’ll get no added info about the path from using a basic <input type=’file’> tag. The same restrictions apply. Using the input tag, you’ll have to do a bit more work to get to the file bytes. You can get to each uploaded file in a postback by using Request.Files. This will give you every HttpFileUpload in the request, regardless of if you use a <input type=’file’> or a FileUpload control. If using the input tag, you can set the runat=’server’ and id attributes to access it from server side code. You can then access it’s PostedFile in postback. Each object in Request.Files and each PostedFile of each <input type=’file’ runat=’server> and also each PostedFile of each FileUpload is of type HttpFileUpload. That class also has a SaveAs method that does exactly what you’d expect it to. If you need to access the stream, then it has an Inputstream property. You can use it to read the contents using a StreamReader as I’ve shown above. If you need to access the bytes, the following code will help [please note that HttpFileUpload does not have any direct way to give you all the bytes in a byte array, like the FileUpload control does]:
HttpPostedFile file = Request.Files[0]; //you can use inputid.PostedFile too
Stream str = file.InputStream;
byte[] bytes = new byte[file.ContentLength];
str.Read(bytes, 0, file.ContentLength);
After that, bytes will hold the binary content of the file.
Hope that helps.