Send file using Response.BinaryWrite() and delete it afterwards - asp-classic

As part of a Classic ASP Project the user should be able to download a file - which is dynamicly extracted from a zip archive and sent via Response.BinaryWrite() - by simply calling "document.asp?id=[some id here]".
Extracting and sending is not the problem but I need to delete the extracted file after the download finished. I never did any ASP or VBA before and I guess that's why I stuck here.
I tried deleting the file right after Response.WriteBinary() using FileSystemObject.DeleteFile() but this results in a 404-Error on the client-side.
How can I wait till the download finished and then do additional actions?
Edit: This is how my code looks like:
'Unzip a specified file from an archive and put it's path in *document*
set stream = Server.CreateObject("ADODB.Stream")
stream.Open
stream.Type = 1 ' binary
stream.LoadFromFile(document)
Response.BinaryWrite(stream.Read)
'Here I want to delete the *document*

I suspect that the point you are calling the DeleteFile method the file you are trying delete is currently locked by something else, the question is what?
Try including:-
stream.Close()
after your BinaryWrite. Also make sure you've done a similar thing to the component you've used to extract the file. If the component doesn't offer any obviouse "close" methods they trying assigning Nothing to the variables referencing them.

Is it not possible to stream the file into memory, then binary write the stream to the browser, this way the file is never created on the server and there is no need to delete it.

I found a solution: The extracted files are saved in a special directory and everytime a user runs the document.asp it checks this directory for files older than one hour and deletes them.
I think it's the simplest way to manage, but furthermore I would prefer a solution where the document is deleted after downloading.

Related

Overwrite an existing file programmatically

I have a QDialogBox where there is an option to upload a file.
I can upload files and save them to a folder. It works fine.
But if in case there is a file that already exists in the folder, I am not sure how to handle that scenario.
I want to warn the user that the file with same name already exists.
Is there a Windows API that I can use in this case? (because when we manually save an existing file, we get a warning, how can I use that?)
If someone can point me to that documentation, it will be great.
If you are using a QFileDialog, confirmOverwrite is activated by default, so, if getSaveFileName() returned a non-empty QString, then that means the user accepted to overwrite the file. Other way, you get an empty QString.
Then, you can check if the file exists, and remove it in that case, but you know that the user was Ok with that.
There is always a potential race condition when saving files. Checking to see if the file exists first is not safe, because some other process could create a file with the same name in between the check and when you actually write the file.
To avoid problems, the file must be opened with exclusive access, and in such a way that it immediately fails if it already exists.
If you want to do things properly, take a look at these two answers:
How do I create a file in python without overwriting an existing
file
Safely create a file if and only if it does not exist with
python
You can use QDir::entryList() to get the file names in a directory if you're not using a QFileDialog.
QDir dir("/path/to/directory");
QStringList fileNames = dir.entryList();
Then iterating through file names, you can see if there's a file with the same name. If you need it, I can give an example for that too. It'd be C++, but easily adaptable to Python.
Edit: Smasho just suggested that using QDir::exists() method. You can check if the file name exists in the directory with this method instead of iterating like I suggested.
if(dir.exists(uploadedFileName))

Read from bytestream in asp

I'm wondering if it's possible to read from a bytestream without saving it.
I have a file, wich is a PDF that's in a mailbox. Through code I can access this mailbox and read out the attachements in it (the pdf's) At that point every pdf is in a bystream.
For now I just save it locally to test if my code works. But I need to work without saving the file.
Is there a way so I can get data from that file without saving. I need to process the first page and find the image in there (which is a qr code).
I have code to do this from a local file, but I want this to be directly from on of those in the bystreams.
Can I store the bytesteam in something like an object or a list of bytestreams and use that?

Get file upload data from post data in ASP.NET

I am looping through the posted values on a form with a view to doing something with them (so don't have access to the controls themselves). This is the process I have to take on this project so that is why I'm doing it this way.
On the form I will have a file upload box but I am not sure how I would upload the file that has been selected from it as I can't just do Control.SaveAs(). When I return the posted value using Request.Form.Item[i] I get the file name I chose but not the full path like I would expect.
Can someone point me in the right direction please?
Thanks.
If you want to manipulate the uploaded files directly, and not through a FileUploader control, you should use the Request.Files collection and not the Request.Form
File Upload controls only pass the file name and the contents. I'm not sure why you would need a folder name, especially since the folder name would be for the client - I can't expect that this would have any value to you since you want to save the file on the server.
As I am unsure of your goals, I would recommend using Server.MapPath("~/Folder") to find a suitable folder to save your uploaded files to

how to check whether a file exists before creating it

I am creating an xml file. I need to check first if the file exists or not. If the file does not exist, create it and add the data cmg from a .cs file.
If the file exists, don't create the file just add the data cmg from a .cs file.
My code looks like this:
string filename="c:\\employee.xml";
XmlTextWriter tw=new XmlTextWriter(filename,null);//null represents
the Encoding Type//
tw.Formatting=Formatting.Indented; //for xml tags to be indented//
tw.WriteStartDocument(); //Indicates the starting of document (Required)//
tw.WriteStartElement("Employees");
tw.WriteStartElement("Employee","Genius");
tw.WriteStartElement("EmpID","1");
tw.WriteAttributeString("Name","krishnan");
tw.WriteElementString("Designation","Software Developer");
tw.WriteElementString("FullName","krishnan Lakshmipuram Narayanan");
tw.WriteEndElement();
tw.WriteEndElement();
tw.WriteEndDocument();
tw.Flush();
tw.Close();
so next time we add data to file we need to check if the file exits and add data to xml file
and as we have made empID as a primary key, if user tries to make duplicate entry we need to avoid
Is this possible to do?
if (!File.Exists(filename))
{
// create your file
}
or
if (File.Exists(filename))
{
File.Delete(filename);
}
// then create your file
File class is in System.IO namespace (add using System.IO; to your file)
You can't append records to an XML file, you have to read the file and then rewrite it.
So, just check if the file exists, and read the records from it. Then write the file including all previous records and the new record.
Have a look at the File.Exists method here
Testing for existance of a file before attempting to create it inherently is subject to a "things change after check" race condition. Who can guarantee you that your application isn't preempted and put to sleep for a moment after you checked, someone else creates/deletes that file, your app gets to run again and does exactly the opposite of what you intended ?
Windows (as well as all UN*X variants) supports file open/create modes that allow to perform that create-if-nonexistant/open-if-existant operation as a single call.
As far as .NET goes, this means for your task (create an XML file) you'd first create a System.IO.FileStream with the appropriate modes, see http://msdn.microsoft.com/en-us/library/system.io.filemode.aspx and then pass that stream to the XmlWriter constructor. That's safer than simply performing an "exists" check and hoping for the best.

Working with big files in classic ASP

I was wondering what's the best practise for serving a generated big file in classic asp.
We have an application with "export to excel" function that produces 10MB files. The excels are created by just calling a .asp page that has the Response.ContentType set to excel and has an HTML table for the data.
This gives as problem that it takes 4 minutes before the user sees the "Save as..." dialog.
My current solution is to call an .asp page that creates the excel on the server with AJAX and lets the page return the URL of the generated document. Then I can use javascript to display the on the original page.
Is this easy to do with classic asp (creating files on server with some kind of stream) while keeping security in mind? (URL should make people be able to guess the location of other files)
How would I go about handling deleted the generated files overtime? They have to be deleted periodicly as the data changes in realtime.
Thanks.
edit: I realized now that creating the file on the server will probably also take 4 minutes...
I think you are selecting a complex route, when the solution is simple enough (Though I may be missing some requirements)
If you to generate an excel, just call an asp page that do the following:
Response.clear
Response.AddHeader "content-disposition", "attachment; filename=myexcel.xls"
Response.ContentType = "application/excel"
'//write the content of the file
Response.write "...."
Response.end
This will a start a download process in the browser without needing to generate a extra call, javascript or anything
See this question for more info on the format you will choose to generate the excel.
Edit
Since Thomas update the question and the real problem is that the file take 4 minutes to generate, the solution could be:
Offer the user the send the file by email (if this is a workable solution in you server or hosting).
Generate the file async, and let the user know when the file generation is done (with an ajax call, like SO does when other user have added an answer)
To generate the file on the server
'//You should change for a random name or something that makes sense
FileName = "C:\temp\myexcel.xls"
FileNumber = FreeFile
Open FileName For Append As #FileNumber
'//generate the content
TheRow = "...."
Print #FileNumber, TheRow
Close #FileNumber
To delete the temp files generated
I use Empty Temp Folders a freeware app that I run daily on the server to take care of temp files generated. (Again, it depends on you server or hosting)
About security
Generate the files using random numbers or GUIds for a light protection. If the data is sensitive, you will need to download the file from a ASP page, but I think that you will be in the same problem again...(waiting 4 minutes to download)
Read file using FSO.
Set headers for Excel file-type, name according to file read and for download (attachment)
Flush response after headers are set. The client should display "save as" dialogue.
Output FSO to response. Client will download file and see progress bar.
How do you plan to generate the Excel? I hope you don't plan to call Excel to do that, as it is unsupported, and generally won't work well.
You should check to see if there are COM components to generate Excel that you can call from Classic ASP. Alternatively, add one ASP.NET page for the purpose. I know for a fact that there are compoonents that can be called from ASP.NET pages to do this. Worse come to worst, there's an Excel exporter component from Infragistics that works with their UltraWebGrid control to export. The grid need not be visible in order to accomplish this, but styles in the grid translate to styles in the spreadsheet. They also allow you to manipulate the spreadsheet programmatically.

Resources