[asp.net] File genereren en sturen naar client

Pagina: 1
Acties:

  • Rodyman
  • Registratie: November 2001
  • Laatst online: 08-06-2024
Ik heb een asp.net control wat de mogelijkheid biedt om met behulp van de #ZipLib een aantal bestanden te laten zippen en deze te sturen naar de client (de browser).
Wat ik momenteel doe is het volgende:

- user kiest bestanden
- control genereert /test.zip
- control stuurt /test.zip op via response.writeFile()

Nu wordt elke keer /test.zip overschreven met een nieuwe zip file. Maar ik kan me voorstellen dat dit niet goed gaat wanneer er tegelijkertijd twee verschillende users een zip file genereren. Ook is het niet bevorderlijk voor mijn webspace dat er telkens een extra zipfile op de server staat, maar die zou ik natuurlijk gewoon kunnen verwijderen nadat hij gedownload is.

Maar wat ik eigenlijk wil bereiken is dat ik een zip file genereer op een plek die alleen voor die huidige user zichtbaar is en ook weer automatisch leeggehaald wordt op het moment dat de user zijn browser sluit. Soort van sessie idee zegmaar? Maar dit heb ik na een hoop zoeken op google/got nog niet kunnen vinden.

Een andere (minder mooie) oplossing lijkt mij dat ik met timestamps/random numbers moet gaan werken om dit te omzeilen?

Kan iemand me in de goede richting schoppen misschien? Het lijkt me dat dit probleem vaker voor moet komen.

  • mulder
  • Registratie: Augustus 2001
  • Laatst online: 11-04 20:37

mulder

ik spuug op het trottoir

Je zou de sessie id in de filename of directory kunnen verwerken, of je moet zorgen dat je het zipje naar de browser streamt ipv naar een file.

oogjes open, snaveltjes dicht


  • ZroBioNe
  • Registratie: Augustus 2001
  • Niet online
Je moet de file dan ook niet op de schijf op slaan, maar dmv een stream in de page houden.
Nadat je de zipstream hebt kan je doen:
Visual Basic .NET:
1
2
Response.Write(zipStream)
Response.End()


Volgens mij moet je dan ook nog een header meegeven, maar dat moet je even opzoeken.

edit:

Ik had don fuanco niet gelezen |:(

[ Voor 10% gewijzigd door ZroBioNe op 14-02-2006 10:15 ]


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Idd maak gewoon een HttpHandler die de zip in het geheugen creeert en dan naar de gebruiker streamt. Dan heb je ook meteen geen probleem meer dat andere users bijvoorbeeld ook tijdelijk die zip kunnen downloaden.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Mastermind
  • Registratie: Februari 2000
  • Laatst online: 05-04 18:13
Werkt dit?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//noem de filename van de control alsvolgt, deze maakt een unieke naam.
string filename = "test" + Guid.NewGuid().ToString() + ".zip";

//schrijft tempfile met unieke naam naar user als test.zip
Response.ClearContent();
            Response.ClearHeaders();
            Response.AddHeader ("Content-Disposition", "attachment;filename=test.zip");
            Response.ContentType = "application/zip";

            Response.WriteFile(filename);
            //ok = SendBinaryFile(response, fileName);

            Response.Flush();
            Response.Close();

//delete tempfile
try
            {
                System.IO.File.Delete(filename); //Remove Tempfile
            }
            catch{};

  • Rodyman
  • Registratie: November 2001
  • Laatst online: 08-06-2024
ZroBioNe schreef op dinsdag 14 februari 2006 @ 10:15:
Je moet de file dan ook niet op de schijf op slaan, maar dmv een stream in de page houden.
Nadat je de zipstream hebt kan je doen:
Visual Basic .NET:
1
2
Response.Write(zipStream)
Response.End()


Volgens mij moet je dan ook nog een header meegeven, maar dat moet je even opzoeken.

edit:

Ik had don fuanco niet gelezen |:(
Ok ik heb dit geprobeerd maar het enige wat er nu in de file komt te staan is:

"System.IO.MemoryStream"

Ik heb de code aangepast dat ik in plaats van naar een file schrijf, naar een memorystream schrijf. Daarna wil ik deze wegschrijven naar de output file. Hieronder volgt de code die ik nu heb, maar ik krijg het niet voor elkaar de stream weg te schrijven met response.write.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        // Get the full path
        DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath(_directory));
        FileInfo[] aFilenames = dirInfo.GetFiles("*.jpg");

        // the name of the Zip File is the second Parameter passed in calling
        MemoryStream stream = new MemoryStream();

        ZipOutputStream s = new ZipOutputStream(stream);

        // Set compression level: 0 [none] - 9 [highest]
        s.SetLevel(5);

        for (int i = 0; i < aFilenames.Length; i++) {
            FileStream fs = File.OpenRead(aFilenames[i].FullName);

            // normally, the Buffer is allocated once,
            // here we do it once per File for clarity's sake
            byte[] buffer = new byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);

            // and now we write a ZipEntry & the Data
            ZipEntry entry = new ZipEntry(aFilenames[i].FullName);
            s.PutNextEntry(entry);
            s.Write(buffer, 0, buffer.Length);
        }

        s.Finish();
        s.Close();

        Response.ClearContent();
        Response.ClearHeaders();
        // Specify it is a zipfile
        Response.ContentType = "application/zip";
        // Set the name for the download dialog
        Response.AddHeader("Content-Disposition", "inline; filename=" + "test.zip");
        Response.Write(stream);
        Response.Flush();
        Response.End();

        stream.Close();

[ Voor 5% gewijzigd door Rodyman op 14-02-2006 12:33 ]


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 11:40

Janoz

Moderator Devschuur®

!litemod

Don Facundo schreef op dinsdag 14 februari 2006 @ 10:09:
Je zou de sessie id in de filename of directory kunnen verwerken, of je moet zorgen dat je het zipje naar de browser streamt ipv naar een file.
Dit gaat natuurlijk weer mis wanneer 1 gebruiker meerdere bestanden gaat downloaden.

Is er in .net een methode waarmee je een tempfile aanmaakt die gegarandeerd uniek is en ook weer wordt verwijderd wanneer je klaar bent? In java kun je iets doen als File.createTempFile(). Kan me moelijk voorstellen dat er voor .net niet iets vergelijkbaars is.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Mastermind
  • Registratie: Februari 2000
  • Laatst online: 05-04 18:13
Janoz schreef op dinsdag 14 februari 2006 @ 11:46:
[...]


Dit gaat natuurlijk weer mis wanneer 1 gebruiker meerdere bestanden gaat downloaden.

Is er in .net een methode waarmee je een tempfile aanmaakt die gegarandeerd uniek is en ook weer wordt verwijderd wanneer je klaar bent? In java kun je iets doen als File.createTempFile(). Kan me moelijk voorstellen dat er voor .net niet iets vergelijkbaars is.
Zie mijn code.

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Janoz schreef op dinsdag 14 februari 2006 @ 11:46:
[...]


Dit gaat natuurlijk weer mis wanneer 1 gebruiker meerdere bestanden gaat downloaden.

Is er in .net een methode waarmee je een tempfile aanmaakt die gegarandeerd uniek is en ook weer wordt verwijderd wanneer je klaar bent? In java kun je iets doen als File.createTempFile(). Kan me moelijk voorstellen dat er voor .net niet iets vergelijkbaars is.
Ik zou niet uit mijn hoofd weten of zoiets bestaat ( Zegt natuurlijk niet dat het niet bestaat ), maar ik kan me niet voorstellen waarom je dat hier zou willen. Het is toch veel handiger om het gewoon in je geheugen te houden, te streamen en dan weer weg te gooien uit je geheugen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 11:40

Janoz

Moderator Devschuur®

!litemod

Jouw code is daarvan inderdaadn een implementatie. ALs je echter naar de implementatie in Java kijkt (werkend linkje) dan zie je dat deze ietsje uitgebreider is. Dingen als 'default aanmaken in temp directory en garanties omtrend uniekheid van het bestand en verwijderen van het bestand wanneer de applicatie afgesloten wordt' zitten maar gedeeltelijk in jouw code ;).

[ Voor 4% gewijzigd door Janoz op 14-02-2006 12:43 . Reden: Linkje gefixed ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 11:40

Janoz

Moderator Devschuur®

!litemod

rwb schreef op dinsdag 14 februari 2006 @ 11:53:
[...]

Ik zou niet uit mijn hoofd weten of zoiets bestaat ( Zegt natuurlijk niet dat het niet bestaat ), maar ik kan me niet voorstellen waarom je dat hier zou willen. Het is toch veel handiger om het gewoon in je geheugen te houden, te streamen en dan weer weg te gooien uit je geheugen.
Eens, mits het zip component daadwerkelijk streaming werkt, de op te leveren bestanden klein of de frequentie van de actie laag is. Stel het zip component creeerd het volledige bestand in het geheugen. Bij grote bestanden en/of veel aanvragen zit het geheugen dan al snel vol. In dat geval laat ik het liever oplossen door de caching van het file systeem (waardoor het eventueel in het geheugen blijft) dan door het virtueel geheugen (waardoor het eventueel op de schijf terecht komt).

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Janoz schreef op dinsdag 14 februari 2006 @ 12:02:
[...]


Eens, mits het zip component daadwerkelijk streaming werkt, de op te leveren bestanden klein of de frequentie van de actie laag is. Stel het zip component creeerd het volledige bestand in het geheugen. Bij grote bestanden en/of veel aanvragen zit het geheugen dan al snel vol. In dat geval laat ik het liever oplossen door de caching van het file systeem (waardoor het eventueel in het geheugen blijft) dan door het virtueel geheugen (waardoor het eventueel op de schijf terecht komt).
Ok als het grote bestanden zijn en het component ondersteunt geen streaming dan is het idd handiger om het in een temp bestand op het filesysteem te doen. Ik zou het dan zo oplossen als mastermind voordraagt met een GUID je in pseudo code doen je dan zo
code:
1
2
3
4
5
6
7
string filename = iets met guid of een ander uniek id
Zipcomponent.CreateZip( filename )
Zet de goede headers
Response.WriteFile( filename );
Response.Flush();
Response.Close();
DeleteFile( filename );

Zo ben je er ook van gegarandeerd dat je bestand na het oversturen weer weg is van je filesystem.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Mastermind
  • Registratie: Februari 2000
  • Laatst online: 05-04 18:13
Lieverds kijk nou eens naar de code die ik gepost heb, die is kant en klaar en moet werken...

  • Rodyman
  • Registratie: November 2001
  • Laatst online: 08-06-2024
Mastermind schreef op dinsdag 14 februari 2006 @ 12:22:
Lieverds kijk nou eens naar de code die ik gepost heb, die is kant en klaar en moet werken...
Inderdaad dat moet werken, maar zoals ik al aangaf zou ik liever een stream sturen zodat ik sowieso geen bestanden op mijn server krijg. Maar dit kreeg ik niet werkend, zie mijn bovenstaande code.

  • Riegstar
  • Registratie: Februari 2003
  • Niet online

Riegstar

Wadapatja!

Misschien heb je hier wat aan (niet getest):
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
private void FileToOutput(ZipOutputStream outputStream, string file, string entryPath, int maximumBufferSize)
{
    ZipEntry entry = new ZipEntry(entryPath);
    FileInfo fileInfo = new FileInfo(file);
    entry.DateTime = fileInfo.LastWriteTime;
    entry.ExternalFileAttributes = (int)fileInfo.Attributes;
    entry.Size = fileInfo.Length;

    entry.CompressionMethod = CompressionMethod.Deflated;

    FileStream fileStream = File.OpenRead(file);

    try 
    {
        byte[] transferBuffer;
        if (fileStream.Length > maximumBufferSize)
            transferBuffer = new byte[maximumBufferSize];
        else
            transferBuffer = new byte[fileStream.Length];

        outputStream.PutNextEntry(entry);

        int bytesRead;
        do 
        {
            bytesRead = fileStream.Read(transferBuffer, 0, transferBuffer.Length);
            outputStream.Write(transferBuffer, 0, bytesRead);
        }
        while (bytesRead > 0);
    }
    finally 
    {
        fileStream.Close();
    }
}

DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath(_directory));
FileInfo[] aFilenames = dirInfo.GetFiles("*.jpg");

// the name of the Zip File is the second Parameter passed in calling
MemoryStream stream = new MemoryStream();

ZipOutputStream s = new ZipOutputStream(stream);

// Set compression level: 0 [none] - 9 [highest]
s.SetLevel(5);

for (int i = 0; i < aFilenames.Length; i++)
{
    FileToOutput(s, aFilenames[i].FullName, aFilenames[i].Name, 4096);
}

Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader ("Content-Disposition", "attachment;filename=test.zip");
Response.ContentType = "application/zip";

Response.Write(stream);

Response.Flush();
Response.Close();

s.Close();
stream.Close();

[ Voor 3% gewijzigd door Riegstar op 14-02-2006 12:48 ]


  • Rodyman
  • Registratie: November 2001
  • Laatst online: 08-06-2024
Riegstar schreef op dinsdag 14 februari 2006 @ 12:46:
Misschien heb je hier wat aan (niet getest):
C#:
1
code code code...
Hij doet het in principe wel, maar ik blijf het probleem houden dat het enige wat er in test.zip komt te staan is:

"System.IO.MemoryStream"

Volgens mij schrijf ik iets niet goed weg ofzo, maar ik kan maar niet vinden wat.

[ Voor 4% gewijzigd door Rodyman op 14-02-2006 12:57 ]


  • Riegstar
  • Registratie: Februari 2003
  • Niet online

Riegstar

Wadapatja!

Hier al gekeken: codeproject

Nog een link: Forum van SharpZipLib

Meer kan ik niet doen voor je....

[ Voor 45% gewijzigd door Riegstar op 14-02-2006 13:10 ]


  • Rodyman
  • Registratie: November 2001
  • Laatst online: 08-06-2024
ahh ik denk dat ik hier wel iets mee kan: http://community.sharpdevelop.net/forums/thread/4031.aspx

Ik heb er nu geen tijd voor, vanavond zal ik het eens proberen en als het werkt post ik hier de oplossing wel! Alvast bedankt allemaal voor jullie hulp!

  • Rodyman
  • Registratie: November 2001
  • Laatst online: 08-06-2024
En zo werkt het perfect:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
        // Get the full path
        DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath(_directory));
        FileInfo[] aFilenames = dirInfo.GetFiles("*.jpg");

        // the name of the Zip File is the second Parameter passed in calling
        MemoryStream stream = new MemoryStream();

        ZipOutputStream s = new ZipOutputStream(stream);

        // Set compression level: 0 [none] - 9 [highest]
        s.SetLevel(1);

        for (int i = 0; i < aFilenames.Length; i++) {
            FileStream fs = File.OpenRead(aFilenames[i].FullName);

            // normally, the Buffer is allocated once,
            // here we do it once per File for clarity's sake
            byte[] buffer = new byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);

            // and now we write a ZipEntry & the Data
            ZipEntry entry = new ZipEntry(aFilenames[i].FullName);
            s.PutNextEntry(entry);
            s.Write(buffer, 0, buffer.Length);
        }

        s.Finish();
        s.Close();

        byte[] result = stream.ToArray();

        Response.ClearContent();
        Response.ClearHeaders();
        // Specify it is a zipfile
        Response.ContentType = "application/zip";
        // Set the name for the download dialog
        Response.AddHeader("Content-Disposition", "inline; filename=" + "test.zip");
        Response.BinaryWrite(result);
        Response.End();

        stream.Close();


Oftewel van de stream mbv toarray een bytearray maken. .ToArray() flushed de complete inhoud van de memorystream naar een byte array die daarna met response.BinaryWrite naar de client gestuurd kan worden.

Dus probleem opgelost, geen files meer op de server en zoveel synchrone aanroepen als ik maar wil!
Pagina: 1