locked
System.IO.FileNotFoundException Trying to Zip Files From Document Library RRS feed

  • Question

  • I'm trying to create a custom download feature that allows users to select items from a document library and download them as a zip file.  I have a good portion of it working.  However, I'm not sure how to grab the file from sharepoint to pass to the zip function.  I'm using SharpZipLib compression library.  The full error I'm getting is:

    System.IO.FileNotFoundException: Could not find file 'c:\windows\system32\inetsrv\GRT_WLF_brkfstbuffet_425.jpg'.
    File name: 'c:\windows\system32\inetsrv\GRT_WLF_brkfstbuffet_425.jpg'

    Here's my code.  The serialization stuff and everything else is working, I just can't figure out how to get the file path:

            internal static bool AssetDownload(string AssetDownloads)
            {
                bool success = false;
                try
                {
                    string compressedFileName = "JamesTest";
                    // Add headers for zip download:
                    System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + compressedFileName + ".zip");
                    System.Web.HttpContext.Current.Response.ContentType = "application/zip";
                    // Create the Zip and add the files:
                    using (var zipStream = new ZipOutputStream(System.Web.HttpContext.Current.Response.OutputStream))
                    {
                    
                        /* "AssetDownloads" is a json array of objects:
                         *      AssetDownloads[i].Data.ID
                         *      AssetDownloads[i].Data.UsedFor
                         * Need to parse out this information:
                         */
                        JavaScriptSerializer serializer = new JavaScriptSerializer();
                        var downloads = serializer.Deserialize<List<AssetDownload>>(AssetDownloads);
                        foreach (AssetDownload download in downloads)
                        {
                            // Grab the Digital Asset object so we can get the file to add to the zip:
                            BrandAsset ba = new BrandAsset(download.ID);
                            byte[] fileBytes = System.IO.File.ReadAllBytes(ba.File.Name);
                            var fileEntry = new ZipEntry(System.IO.Path.GetFileName(ba.File.Name))
                            {
                                Size = fileBytes.Length
                            };
                            zipStream.PutNextEntry(fileEntry);
                            zipStream.Write(fileBytes, 0, fileBytes.Length);
                            // Add the file to the zip:
                            Util.Log("Yep - ID = " + download.ID + " UsedFor = " + download.UsedFor);
                        }
                        zipStream.Flush();
                        zipStream.Close();
                    }
                }
                catch (Exception err) { success = false; Util.Log(err.ToString()); }
                return success;
            }


    James

    Wednesday, October 31, 2012 5:47 PM

Answers

  • Nevermind, you can ignore this post.  I ended up submitting the form to itself instead of using ajax and that did the trick.

    James

    • Proposed as answer by Hemendra Agrawal Thursday, November 1, 2012 6:08 AM
    • Marked as answer by Lhan Han Monday, November 12, 2012 1:26 AM
    Wednesday, October 31, 2012 8:56 PM

All replies

  • OK, I found a possible solution at http://www.deviantpoint.com/post/2010/05/08/SharePoint-2010-Download-as-Zip-File-Custom-Ribbon-Action.aspx

    I implemented the code and don't seem to be getting any errors.  However I'm not getting asked to download the zipped file.  I believe this has to do with the Response.  First indication is that when is that I have to reference "Response" as "System.Web.HttpContext.Current.Response" to avoid the compile error "the name Response doesn't exist in the current context".

    I'm doing an Ajax call to a function as well so I'm not sure if the Response actually exists (which would explain why i get that compile error.  Below is all the code.  If anyone can help it would be appreciated:

    namespace GWR.CreativeServices
    {
        public class BrandAsset
        {
            #region Properties
            #endregion
            #region Constructors
            #endregion
            #region Initalize the object's members
            #endregion
            #region GetLatestItemID()
            #endregion
            #region MultipleUploadSubmit()
            /// <summary>
            /// tags common metadata to batch upload
            /// </summary>
            /// <returns>bool success</returns>
            #endregion
            #region AssetDownload()
            /// <summary>
            /// 
            /// </summary>
            /// <returns>bool success</returns>
            internal static bool AssetDownload(string AssetDownloads)
            {
                bool success = false;
                try
                {
                    
                    using (MemoryStream ms = new MemoryStream())   
                    {
                        using (ZipFileBuilder builder = new ZipFileBuilder(ms))
                        {
                            /* "AssetDownloads" is a json array of objects:
                             *      AssetDownloads[i].Data.ID
                             *      AssetDownloads[i].Data.UsedFor
                             * Need to parse out this information:
                             */
                            JavaScriptSerializer serializer = new JavaScriptSerializer();
                            var downloads = serializer.Deserialize<List<AssetDownload>>(AssetDownloads);
                            foreach (AssetDownload download in downloads)
                            {
                                // Grab the Digital Asset object so we can get the file to add to the zip:
                                BrandAsset ba = new BrandAsset(download.ID);
                                AddFile(builder, ba.File, string.Empty);  
                                // Add the file to the zip:
                                Util.Log("Yep - ID = " + download.ID + " UsedFor = " + download.UsedFor);
                            }
                            builder.Finish();
                            WriteStreamToResponse(ms);  
                        }
                    }
                }
                catch (Exception err) { success = false; Util.Log(err.ToString()); }
                return success;
            }
            #endregion
            private static void AddFile(ZipFileBuilder builder, SPFile file, string folder)
            {
                using (Stream fileStream = file.OpenBinaryStream())
                {
                    builder.Add(folder + "\\" + file.Name, fileStream);
                    fileStream.Close();
                }
            }
            private void AddFolder(ZipFileBuilder builder, SPFolder folder, string parentFolder)
            {
                string folderPath = parentFolder == string.Empty ? folder.Name : parentFolder + "\\" + folder.Name;
                builder.AddDirectory(folderPath);
                foreach (SPFile file in folder.Files)
                {
                    AddFile(builder, file, folderPath);
                }
                foreach (SPFolder subFolder in folder.SubFolders)
                {
                    AddFolder(builder, subFolder, folderPath);
                }
            }
            private static void WriteStreamToResponse(MemoryStream ms)
            {
                if (ms.Length > 0)
                {
                    Util.Log("REsponse = " + System.Web.HttpContext.Current.Response.ToString());
                    string filename = DateTime.Now.ToFileTime().ToString() + ".zip";
                    System.Web.HttpContext.Current.Response.Clear();
                    System.Web.HttpContext.Current.Response.ClearHeaders();
                    System.Web.HttpContext.Current.Response.ClearContent();
                    System.Web.HttpContext.Current.Response.AddHeader("Content-Length", ms.Length.ToString());
                    System.Web.HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
                    System.Web.HttpContext.Current.Response.ContentType = "application/octet-stream";
                    byte[] buffer = new byte[65536];
                    ms.Position = 0;
                    int num;
                    do
                    {
                        num = ms.Read(buffer, 0, buffer.Length);
                        System.Web.HttpContext.Current.Response.OutputStream.Write(buffer, 0, num);
                    }
                    while (num > 0);
                    System.Web.HttpContext.Current.Response.Flush();
                }
            }
        }
    }
    [Serializable]
    public class AssetDownload {
        public string ID { get; set; }
        public string UsedFor { get; set; }
    }
    public class ZipFileBuilder : IDisposable   
    {  
        private bool disposed = false;  
        ZipOutputStream zipStream = null;   
        protected ZipOutputStream ZipStream   
        {   
            get { return zipStream; }   
        }   
        ZipEntryFactory factory = null;   
        private ZipEntryFactory Factory   
        {  
            get { return factory; }   
        }   
        public ZipFileBuilder(Stream outStream)  
        {   
            zipStream = new ZipOutputStream(outStream);  
            zipStream.SetLevel(9); //best compression   
            factory = new ZipEntryFactory(DateTime.Now);   
        }   
        public void Add(string fileName, Stream fileStream)  
        {  
            //create a new zip entry              
            ZipEntry entry = factory.MakeFileEntry(fileName);  
            entry.DateTime = DateTime.Now;  
            ZipStream.PutNextEntry(entry);  
            byte[] buffer = new byte[65536];  
            int sourceBytes;   
            do  
            {   
                sourceBytes = fileStream.Read(buffer, 0, buffer.Length);   
                ZipStream.Write(buffer, 0, sourceBytes);   
            }   
            while (sourceBytes > 0);   
        }   
        public void AddDirectory(string directoryName)   
        {   
            ZipEntry entry = factory.MakeDirectoryEntry(directoryName);   
            ZipStream.PutNextEntry(entry);  
        }   
        public void Finish()  
        {   
            if (!ZipStream.IsFinished)   
            {   
                ZipStream.Finish();   
            } 
        }   
        public void Close()  
        {   
            Dispose(true);   
            GC.SuppressFinalize(this);  
        }  
        public void Dispose()  
        {   
            this.Close();   
        }   
        protected virtual void Dispose(bool disposing)   
        {   
            if (!disposed)   
            {   
                if (disposing)  
                {   
                    if (ZipStream != null)   
                        ZipStream.Dispose();   
                }   
            }   
            disposed = true;   
        }   
    }


    James

    Wednesday, October 31, 2012 6:52 PM
  • The current response is the problem as suspected.  If I use the above on the "page_load" event it works fine (I'm asked to download the zip file).  Does anyone know how to use the "HttpContext.Current.Response" through ajax by chance (if that makes sense)?  I'll post more as I do some research.  I'm wondering if it exists if I would just have the page post back to itself instead of doing the ajax call?

    James

    Wednesday, October 31, 2012 7:09 PM
  • Nevermind, you can ignore this post.  I ended up submitting the form to itself instead of using ajax and that did the trick.

    James

    • Proposed as answer by Hemendra Agrawal Thursday, November 1, 2012 6:08 AM
    • Marked as answer by Lhan Han Monday, November 12, 2012 1:26 AM
    Wednesday, October 31, 2012 8:56 PM