Compress a file open on another application

  • (2 Pages)
  • +
  • 1
  • 2

16 Replies - 7958 Views - Last Post: 08 August 2011 - 04:29 AM Rate Topic: -----

#1 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Compress a file open on another application

Posted 31 July 2011 - 02:28 PM

Hello!

I have a program I made in vb.net express 2008 that used java.utils.zip to compress my work files to a Zip archive that I ran occassionaly to have a backup. I worked fine, but with net framework 4 and vb.net 2010 it doesn't work. So I modified it to use sharpziplib and it works fine if all files on the filter list in the folder are closed, but if I have a file open in OpenOffice writer, my program can't access it and won't create the zip file. The file that usually stays open all the time is my TODO list, that is updated several times a day , so usually gets printed, and updated( adding or deleting entries), without closing it.

Is there a way to read a file or to load a copy into memory and process it from there without closing it in the other application?

Here it the module:

Imports System
Imports System.IO
Imports ICSharpCode.SharpZipLib.Core
Imports ICSharpCode.SharpZipLib.Zip
Module ZipClass

    Public Sub CreateSample(ByVal outPathname As String, ByVal password As String, ByVal folderName As String)
        Dim ExtensionsToCompress As String = ".TXT_.REC_.REP_.ODS_.ODT_.DOC_.XLS_.RTF"
        Dim Filter As String
        Dim fsOut As FileStream = File.Create(outPathname)
        Dim zipStream As New ZipOutputStream(fsOut)

        zipStream.SetLevel(3)   '0-9, 9 being the highest level of compression
        zipStream.Password = password   ' optional. Null is the same as not setting.
        Dim files As String() = Directory.GetFiles(folderName)

        For Each filename As String In files

            Dim fi As New FileInfo(filename)
            Filter = UCase(Path.GetExtension(filename))

            If filename.Contains(".zip") Then ' <> Form1.ThePath & String.Format("{0:MMMddyy}", DateTime.Now) & ".zip" Then
            Else
                If ExtensionsToCompress.Contains(Filter) Then

                    Dim entryName As String = ZipEntry.CleanName(filename) ' Removes drive from name and fixes slash direction
 
                    Dim newentry As New ZipEntry(Path.GetFileName(filename)) '' No Path, Only FileName

                    newentry.DateTime = fi.LastWriteTime    ' Note the zip format stores 2 second granularity
                    ' Specifying the AESKeySize triggers AES encryption. Allowable values are 0 (off), 128 or 256.
                    '   newEntry.AESKeySize = 256;

                    ' To permit the zip to be unpacked by built-in extractor in WinXP and Server2003, WinZip 8, Java, and other older code,
                    ' you need to do one of the following: Specify UseZip64.Off, or set the Size.
                    ' If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, you do not need either,
                    ' but the zip will be in Zip64 format which not all utilities can understand.
                    '   zipStream.UseZip64 = UseZip64.Off;
                    newentry.Size = fi.Length

                    zipStream.PutNextEntry(newentry)

                    ' Zip the file in buffered chunks
                    ' the "using" will close the stream even if an exception occurs
                    Dim buffer As Byte() = New Byte(4095) {}
                    Using streamReader As FileStream = File.OpenRead(filename)
                        StreamUtils.Copy(streamReader, zipStream, buffer)
                    End Using

                    zipStream.CloseEntry()


                End If

            End If
        Next
        zipStream.IsStreamOwner = True  ' Makes the Close also Close the underlying stream
        zipStream.Close()
    End Sub

End Module



Any help will be greatly appreciated

ricardosms

Is This A Good Question/Topic? 0
  • +

Replies To: Compress a file open on another application

#2 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10816
  • View blog
  • Posts: 40,318
  • Joined: 27-December 08

Re: Compress a file open on another application

Posted 01 August 2011 - 07:05 AM

Moved to VB.NET. Please do not post questions in the tutorials sections.
Was This Post Helpful? 0
  • +
  • -

#3 raziel_  Icon User is offline

  • Like a lollipop
  • member icon

Reputation: 465
  • View blog
  • Posts: 4,255
  • Joined: 25-March 09

Re: Compress a file open on another application

Posted 01 August 2011 - 07:13 AM

what i can think of is you to copy the file and then compress it(the copy). if another process open your file you cant access it through your program. the other thing is that if you copy the file it may contain old data and not the current one. you may want to close the file compress it and then re-open the file to be sure that you will compress the current data in it.

This post has been edited by NoBrain: 01 August 2011 - 07:14 AM

Was This Post Helpful? 0
  • +
  • -

#4 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 01 August 2011 - 12:52 PM

Hi.
Thank you for your response.

How do you copy in VB.Net code a file open by another process?

I used this code and it will skip it, like it doesn't exist:

            If UCase(filename).Contains(".DOC") Then
                If UCase(filename).Contains("TODO.DOC") Then
                    Dim Filetocopy As String = "Todo.doc"
                    Dim TestFile As String = "Test.doc"
                    If System.IO.File.Exists(Filetocopy) = True Then
                        System.IO.File.Copy(Filetocopy, TestFile)
                        MessageBox.Show("Copied")
                    End If
                    filename = TestFile
                    Dim entryName As String = ZipEntry.CleanName(filename)
.
.
. 



Thank you.
Was This Post Helpful? 0
  • +
  • -

#5 trevster344  Icon User is offline

  • The Peasant
  • member icon

Reputation: 224
  • View blog
  • Posts: 1,511
  • Joined: 16-March 11

Re: Compress a file open on another application

Posted 01 August 2011 - 12:55 PM

I ran into this same issue, so I stopped using the library, and just decided to make the whole project simpler. Just start a new process of winrar, and use the command line arguments to do the compressing. Winrar ended up being more useful because it does a far better job compressing files then sharp zip lib ever will. Sorry I can't provide any real help, just thought I'd share that tid bit of information, you might find it to be easier if you want to give it a shot. :)
Was This Post Helpful? 0
  • +
  • -

#6 raziel_  Icon User is offline

  • Like a lollipop
  • member icon

Reputation: 465
  • View blog
  • Posts: 4,255
  • Joined: 25-March 09

Re: Compress a file open on another application

Posted 01 August 2011 - 02:05 PM

as i say it will be better if you close the file compress it and then re-open it since you might get losses of your data.
Was This Post Helpful? 0
  • +
  • -

#7 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 01 August 2011 - 03:08 PM

Thank you for your repplies.

If I create my zip file from within my program, skipping all the *.doc files, I could get to windows explorer and drag my TODO.DOC to the new zip file, but that has to be done manually. The windows utility, as winrar, or winzip or 7zip, don't care if the file is open or not to compress it. But all these applications are outside my program, so I have to do it manually, or close the TODO file, that will defeat the purpose of creating the file from inside my application, on a semi automatic process. My file is edited mostly at the beginning, that information is not critical, so if I lose some of it, won't matter too much, the older entries are toward the end of the file, and are long term items, so they don't change a lot. Any version of my file will be good enough. It is not too practical to close the file, compress it and then open it again.

Any other thoughts?

Regards,
Ricardosms.
Was This Post Helpful? 0
  • +
  • -

#8 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 04 August 2011 - 09:29 PM

Hello:

I have been experimenting with shell32.dll copyhere and I am able to compress files that are in use by other processes.
I can compress everything in a folder with this code:

   Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
'This Compresses everything in the folder
        TextBox1.Text = ""
        Try
            Dim emptyzip() As Byte = New Byte() {80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

            Dim fs As FileStream = File.Create("test.zip")
            fs.Write(emptyzip, 0, emptyzip.Length)
            fs.Flush()
            fs.Close()
            fs = Nothing
            Dim sc As New Shell32.Shell
            Dim SrcFlder As Shell32.Folder = sc.NameSpace("E:\repairs")
            Dim DestFlder As Shell32.Folder = sc.NameSpace("E:\repairs\BAK\test.zip")
            Dim items As Shell32.FolderItems = SrcFlder.Items()
            counter = SrcFlder.Items.Count

            For Each Y As Shell32.FolderItem In SrcFlder.Items

                TextBox1.Text = TextBox1.Text & vbNewLine & Y.Name & " is " & Y.Type.ToString
                '  DestFlder.CopyHere(Y, 16) '20)
            Next

            DestFlder.CopyHere(items, 20)
            While (DestFlder.Items.Count < i)
                System.Threading.Thread.Sleep(1000)
            End While
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        ' Ary.Clear()
    End Sub



This works fairly quick because I copy all the items at the same time with:

DestFlder.CopyHere(items, 20)



But, if I want to Exclude subdirectories, include file types or exclude filetypes, I have to do one at a time and use sleep function to allow the process to finish, otherwise it gives me access error.

This is very slow. I tried creating in advance an array, an arraylist or a combobox with the items to include, and read from there, but I get null reference or type cast errors.

This one skips subfolders and *.gif files:

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        TextBox1.Text = ""

        Try
            Dim emptyzip() As Byte = New Byte() {80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
            Dim fs As FileStream = File.Create("test.zip")
            fs.Write(emptyzip, 0, emptyzip.Length)
            fs.Flush()
            fs.Close()
            fs = Nothing
            Dim sc As New Shell32.Shell
            Dim SrcFlder As Shell32.Folder = sc.NameSpace("E:\repairs")
            Dim DestFlder As Shell32.Folder = sc.NameSpace("E:\repairs\BAK\test.zip")
            Dim items As Shell32.FolderItems = SrcFlder.Items()
            counter = SrcFlder.Items.Count

            For Each Y As Shell32.FolderItem In SrcFlder.Items

                TextBox1.Text = TextBox1.Text & vbNewLine & "  " & Y.Name & " is " & Y.Type.ToString

                If (UCase(Y.Type.ToString).Contains("FOLDER")) Then
                    TextBox1.Text = TextBox1.Text & "------------> Skipped This One "
                    ' counter = counter - 1
                ElseIf UCase(Y.Name).Contains(".GIF") Then
                    TextBox1.Text = TextBox1.Text & "------------> Skipped This One "

                Else
                    DestFlder.CopyHere(Y, 16) '20)
                    System.Threading.Thread.Sleep(1500)

                End If
            Next


       Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        ' Ary.Clear()
    End Sub


And I can revert the if statements to include files like *.txt, *.pdf or *.doc instead of exclude, but,

How can I make a list of items to compress at once instead of one at a time?


Thank you for any feedback that you might have.

Ricardosms
Was This Post Helpful? 0
  • +
  • -

#9 raziel_  Icon User is offline

  • Like a lollipop
  • member icon

Reputation: 465
  • View blog
  • Posts: 4,255
  • Joined: 25-March 09

Re: Compress a file open on another application

Posted 05 August 2011 - 06:38 AM

all i can think of right now is to use ParamArray something like this:

    Private Sub AddFilesToList(ByRef ml As List(Of FileInfo), ByVal ParamArray extensions() As String)
        'Path of the files'
        Dim strPath As String = "C:\test"
        'get the directory info'
        Dim DI As New DirectoryInfo(strPath)
        'search all extensions you want to get'
        For Each ext In extensions
            'add them to array'
            Dim FI() As FileInfo = DI.GetFiles(ext, SearchOption.TopDirectoryOnly)
            'add the to your list'
            For Each f As FileInfo In FI
                ml.Add(f)
            Next
        Next
    End Sub


and here is how you call it:

        Dim MyList As New List(Of FileInfo)
        AddFilesToList(MyList, "*.sys", "*.bat")



using ParamArray you can add as many extensions you want just by using "," as separator and then using DirectoryInfo and FileInfo you can get the extensions you want.
Was This Post Helpful? 0
  • +
  • -

#10 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 05 August 2011 - 01:53 PM

Thank you nobrain

I tried your code, but I don't seem to be able to convert fileinfo to shell32.folderitems. I will keep trying and post the results afterwards.

regards,
ricardosms.

--------------------
Explain me this:

The line below this one is a lie.
The line above this one is true.

Was This Post Helpful? 0
  • +
  • -

#11 raziel_  Icon User is offline

  • Like a lollipop
  • member icon

Reputation: 465
  • View blog
  • Posts: 4,255
  • Joined: 25-March 09

Re: Compress a file open on another application

Posted 05 August 2011 - 03:15 PM

from this:
http://social.msdn.m...0-4d627ec702fe/
Shell32.FolderItem fi = SrcFlder.Items().Item(OriginalFileName);


Was This Post Helpful? 0
  • +
  • -

#12 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 06 August 2011 - 08:44 AM

Hello.
Still fiddling with this.

shell's folderitems and folder's getfiles have different methods and members that I still have to figure out.

In the mean time maybe you could help me with this one:

Is there any way of editing the items collection in shell32.folderitems or create a subset?

like the one used here copyhere(items,options)


Just like a side note for everybody:
java.utils.zip could compress hidden as well as open files.
shell32 can compress open files, but not hidden files.
sharpziplib compresses neither one.
Was This Post Helpful? 0
  • +
  • -

#13 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 07 August 2011 - 05:14 PM

Hello,
It looks that I can't manipulate the "items" object and I can't use paramarray. When I use a loop to add files one at the time to the created zip file, because for every one, a new thread is started on an asynchonuous manner, I get some times access errors, because one thread interferes with the other. I tried checking the file size and allowing more time to finish that thread by using sleep, but I can't trust that it will be enough for every possible situation. So, what I ended doing now is filtering my extensions and copying these files to a temporary directory(not compressed), so the items object for that directory has the desired file objects and I only need one new process, and I can check when the items are all compressed comparing the amount on each one.

   Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click

        Dim objShell As Shell
        Dim objFolder, objFolder1 As Folder

        objShell = New Shell
        objFolder = objShell.NameSpace(AppDomain.CurrentDomain.BaseDirectory & "Temp")
        objFolder1 = objShell.NameSpace(AppDomain.CurrentDomain.BaseDirectory)

        For Each Itm As ShellFolderItem In objFolder1.Items
            If UCase(Itm.Name).EndsWith(".REC") Or UCase(Itm.Name).EndsWith(".REP") Or UCase(Itm.Name).EndsWith(".DOC") _
                Or UCase(Itm.Name).EndsWith(".ODS") Or UCase(Itm.Name).EndsWith(".ODT") Or UCase(Itm.Name).EndsWith(".RTF") Or UCase(Itm.Name).EndsWith(".TXT") Then
                objFolder.CopyHere(AppDomain.CurrentDomain.BaseDirectory & Itm.Name, 16)
            End If
        Next

        objFolder = Nothing
        objShell = Nothing

        Try
            Dim emptyzip() As Byte = New Byte() {80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

            Dim fs As FileStream = File.Create(Format(Now, "MMMddyy") & ".zip")
            fs.Write(emptyzip, 0, emptyzip.Length)
            fs.Flush()
            fs.Close()
            fs = Nothing
            Dim sc As New Shell32.Shell
            Dim SrcFlder As Shell32.Folder = sc.NameSpace(AppDomain.CurrentDomain.BaseDirectory & "Temp")
            Dim DestFlder As Shell32.Folder = sc.NameSpace(AppDomain.CurrentDomain.BaseDirectory & Format(Now, "MMMddyy") & ".zip")
            Dim items As Shell32.FolderItems = SrcFlder.Items()
            counter = SrcFlder.Items.Count

            For Each Y As Shell32.FolderItem In SrcFlder.Items

                TextBox1.Text = TextBox1.Text & vbNewLine & Y.Name & " is " & Y.Type.ToString
                '  DestFlder.CopyHere(Y, 16) '20)
            Next

            DestFlder.CopyHere(items, 20)
            '----------------------------
            Dim i As Integer = SrcFlder.Items.Count
            'Check if all items have been copied to finish operation, check if some are skipped

            While (DestFlder.Items.Count < i)
                System.Threading.Thread.Sleep(1000)
            End While
            '-----------------------------
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
        ' Ary.Clear()

    End Sub



Just going back to an earlier post. I can save my files to disk without having to close them on the application I use. To close and open again the application takes time, but two clicks will save the file. Two of my files are always open, my "To do" list that changes several times a day, and my customer database that changes often, depending on new information for old customers, or new customers. There are overall about twenty files that I like to backup often(Work done, monthly repairs, revenue, credit repairs, my costumers' customers lists...)

I would like someone to add to this thread, because I think my solution is not the best approach, and someone else may have a better solution.

Thank you,

ricardosms
Was This Post Helpful? 0
  • +
  • -

#14 _HAWK_  Icon User is offline

  • Master(Of Foo)
  • member icon

Reputation: 1067
  • View blog
  • Posts: 4,175
  • Joined: 02-July 08

Re: Compress a file open on another application

Posted 07 August 2011 - 06:15 PM

I don't like the idea of leaving files open - that being said an xml file is loaded into memory. So it can be accessed by different means without problem as I have opened mine with my editor and my app is reading and saving while the editor is open. The xmlDocument/XDocument are very fast as most of my queries/edits run b/t 8-20 ms (time from Stopwatch class). I even have a tutorial for encrypting it as well.
Was This Post Helpful? 0
  • +
  • -

#15 ricardosms  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 73
  • View blog
  • Posts: 301
  • Joined: 02-April 10

Re: Compress a file open on another application

Posted 07 August 2011 - 06:50 PM

Hi, hawkvalley1.

Programming and computing in general seems to be a continuous learning process, nothing stays the same for long, languages, operating systems, processors, ideas and solutions. I think sharing ideas is the most important part in this process, because two heads think better than one, not to say thousands.

We spoke before about the lockbits, and after, because your code, I was able to straighten a cople of misconceptions I had, thank you.

Had you had some dealings with the subject of this post? I would like to hear...

Anyway please point me to that tutorial you have and the XML in memory subject.

Thank you.

ricardosms
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2