This article is assumed to be familiar with C # and Windows Forms
Download this article: Zipcompression.exe (150KB)
Summary
When you store a file or send a file over a network, you can save space and network bandwidth using ZIP compression. In addition, the directory structure of the ZIP folder will not be lost, which makes it a very useful compression scheme. The C # language does not have a class that allows you to manipulate the ZIP file, but because the language orientation of the .NET can share the class implementation, and J # publicly open the class in the java.util.zip namespace, so you can use these in the C # code. class. This article will explain how to create a C # application that can compress and down zip files using Microsoft J # class libraries. It will also introduce some other part of the J # runtime that can be used from any .NET compatible language to save some unique parts of certain coding work.
This page
ZIP file and C # Solution Sharpzip enumerate ZIP entries Describe the Zip file Create and modify the Zip file low-level ZIP compressed J # other attractive features application deployment
ZIP is a popular data transfer and storage standard because it can save disk space and network bandwidth. Typical text and database files can be compressed to 10% of their original size. Even if the binary file cannot perform the same compression, 50% compression ratio can be obtained.
An additional advantage of the ZIP file is that a single file can contain multiple files while retain the directory structure. This allows you to send you a full directory tree attached to your email message and let the recipient restore the original file structure.
The ZIP data format is open and will not involve patent or other legal issues. Developers can freely create applications for manipulating ZIP files, and temporarily reduce their own custom data using low-level ZIP compression algorithms. The authors of the ZIP data specification provide developers to developers in a library named Zlib (http://www.gzip.org/zlib). The Java platform uses the library in the Java Development Kit (JDK) version 1.1 to form the basis of the Java Archive (JAR) file format, so starting from the JDK version 1.1, the standard Java Language API contains the manipulated ZIP file. the type. You can find these classes under the java.util.zip namespace.
ZIP file and C #
I hope to use ZIP compression in applications written in C #. Unfortunately, Microsoft .NET Framework currently does not contain any classes for manipulating the ZIP file. However, I did found several products related to ZIP compression. For example, # ziplib (previously known as nziplib, http://www.icsharpcode.net/opensource/sharpziplib/default.asp) is a transplant product of Zlib library to C #. Its license allows developers to include the library in a commercial application of the enclosed source code. However, when MSDN Magazine is printed, # ziplib is still in the pre-release status (version 0.31).
Another solution is to use unmanaged Zlib as a Windows DLL and write the necessary INTEROP packages for it, but because compression involves passing a large amount of data everywhere during each function call, it will be a difficulty in writing INTEROP packaging to get the best performance. the process of. Although other libraries can be used, they are not free.
Back to top
solution
The design of the .NET Framework considers language interoperability. All managed components that follow certain specific rules can be properly used from any .NET compatible programming language that implements the necessary function. The rules and language functions required for interoperability are called public language norms (CLS).
All .NET language compilers implemented by Microsoft are compliant with CLS, including Microsoft Visual J # .NET - a development tool for Java language developers who want to generate applications and services on Microsoft .NET Framework. (Visual J # .NET is developed by Microsoft. It has not been approved and approved by Sun Microsystems, Inc.) This is why you can use the .NET Framework class in a Windows Form and ASP.NET applications written in J #. the reason. Just as you will see later, some classes of the J # runtime are actually in line with CLS, but you can still access most J # classes from other languages so that you don't implement it with .NET Framework Specific functions. Since J # implements JDK version 1.1.4, it will not be unexpectedly, developers can access java.util.zip namespaces through the J # runtime. In the next part of this article, I will introduce an application written with C #, which uses java.util.zip class compressed and uncompressed ZIP files to save space locally and saves bandwidth in the network.
All sample code in this article is developed with Microsoft Visual Studio 2002 and J # Runtuity Version 1.0 (see links at the top of this article).
Back to top
Sharpzip
I used C # to write one of the sample applications that came with this article. Sharpzip. It is a simplified utility used to handle the ZIP file, which can create a zip file or open an existing ZIP file to unpack, attach, and delete files (see Figure 1).
Figure 1 Sharpzip application
Before viewing the code, you need to make sure the J # run library is installed correctly in the system. There is no need to install a complete Visual J # .NET product. You can download and install J # 1.0 Redistributable Package, it can be obtained from http://msdn.microsoft.com/vjsharp/downloads/howtoget.asp.
The java.util.zip namespace is implemented in the VJSLIB.dll program. This assembly is in the C: / WinNT / Microsoft Visual Jsharp .Net / Framework / V1.0.4205 / Directory (you need to replace Winnt to actually Windows directories).
When a reference to VJSlib.dll is included in the project, you can start using J # Namespaces from your code and browse the JDK namespace with an object browser (see Figure 2). Important classes include java.util.zip.zipfile, java.util.zip.ziPentry and java.util.zip.zipoutputstream. These classes are shown in Figure 3, and they can manipulate the ZIP file at the file level.
Figure 2 Namespace in the object browser
When using the methods outlined in this article, the method name may be unfamiliar because Java is different from the naming conventions used by the identifier (except the classes and interfaces). In Java, namespace and method names are written using low-level cases, where the first letter is lowercase, and the other words are the first letters, such as "NEXTELEMENT". However, I am sure you will master this method.
Back to top
Enumerate ZIP entry
The Entries method for the Java.util.zip.zipfile class returns an object that implements the java.util.enumerative interface. Then, the application traverses enumeration to retrieve the ZIPENTRY instance representing each entry in the ZIP file. The ZIPENTRY class will disclose all required information, for example, file name, compression method, timestamp, original size, and compression, etc. (see Figure 4). Note that although the java.util.enumerative interface is similar to the System.Collections.ienumerator interface, the Java enumerator forwards to the next element when you retrieve the current object by calling nextElement, and the .NET enumerator when you call MoveNext Progress in the usability of more elements. Another important difference is that the Enumeration interface does not provide a method for restarting traversal.
One advantage of .NET enumerator is that you can access the current elements multiple times. On the other hand, the Java enumerator enables you to check the completion multiple times, but this is not very useful in most cases. The Java and .NET enumerators have been well designed to prevent you from forgot to advance to the next element within the enumeration cycle.
I decided to write a class for packaging Java enumeors so that I can use the C # foreach statement with them. I name this class EnumerationAdapter. I simulate the reset method by calling the way to return Java enumerator again. To this end, the package constructor uses the entrustment of the java.util.enumerative interface as a parameter, not the java.util.enumerative interface itself as a parameter.
Back to top
Unzip ZIP file
The first thing Sharpzip application is done when decompressed files is that the user specifies the directory that should be created in it. You may have noticed that the application displays the "Browse for Folder" dialog. I tend to use the System.Windows.Forms.Design.FoldernameEditor .FolderBrowser class, but the document claims that the type supports the .NET Framework infrastructure, and is not suitable for direct use, so I will use the Microsoft Shell Controls and Automation Type library, with COM Interop uses shell32 objects.
Extracting the original file from the zip file is very simple: simply call the GetInputStream on the zipfile object and pass the entries you want to get compressed files. The GetInputStream method will produce an InputStream so that you can read the contents of the archive entry from the middle.
The ExtractZipfile Helper function completes this job. Store the directory in the zip file by using a separate entry, but the file name in each entry also contains directory information, so extractzipfile ignores the directory entry and extracts the necessary path information from the file name.
To save a single file to a disk, you only need to write the contents of the InputStream corresponding to the entry of interest. This time I decided not to pack the custom system.io.stream class as Java stream because Java.io namespace has considerable support for streams. In particular, java.io.FileOutputStream enables you to create a file to copy the desired entry.
The CopyStream Helper function in Figure 5 copies the contents of the Java.io.InputStream object to the java.io.outputstream object. The Helper function is also used by other parts of the Sharpzip application. However, you should note that this example does not check if they already exist before overwriting the output file. You may want to prompt the user by querying whether the file should be overwritten. Also note that there is no support for password protection files. You can create your own encryption mechanism using the class in the System.Security.cryptography namespace. If you do this, please note that the resulting file will not be compatible with the standard ZIP utility (for example, Winzip).
Back to top
Create and modify zip files
The Java.util.zip.zipOutputStream class allows you to compress the data and write the results into the basics Java.io.OutputStream object. SHARPZIP applications are suitable for handling files, so it writes compressed data into a new Java.IO.FileoutPutStream object, but you can easily derive your own class from java.io.outputstream, or use one of the standard classes to compress data. Write directly to the network or other storage media.
The CreateemptyzipFile Helper function creates a zip file and close it immediately. The result is a null ZIP file that does not contain any entries. The addition or deletion is not that simple, because the java.util.zip package does not provide random access to the ZIP file. For delete files, you should copy the entries you want to keep to the new ZIP file. For adding files, all entries should be copied to a new ZIP file, then add new entries. The replication entry involves unpacking the entry from the source file in the way I have described, and then recompacked it to the target file.
Create a new ZIpenTry instance for each file you want to add, and Turn SETMETHOD to set the compression method to be used. The supported method is ZIPENTRY.DEFLED (which uses compression algorithm compressed data) and ZIPENTRY.STORED (it stores data but does not apply any compression). Then call zipoutputStream.putNextentry, and incorporate new entries, and then write to its data by calling the write method on the ZipOutputStream object. When the current entry is completed, call ZipOutputStream.Closeentry and continue to process the next entry.
The UpdateZipFile function in Figure 5 updates and deletes the delegate to each entry, so that you can choose which entries should be copied to temporary files. Finally, the new entry is added to the zip file.
Back to top
Low level ZIP compression
Using the Java.util.zip class, not only can compress files, but also compress application data. To illustrate this, I created a pair of functions to use java.util.zip.deflater and java.util.zip.inflater class compression and decompression strings.
The compression function will create an instance of a java.util.zip.deflater class. A parameter definition in the constructor defines the required compression level. Next, I call the deflater.setInput class, and the data to be compressed as the symbolic byte (Sbyte) array, and then call Deflater.Finish.
Please note that in contrast to C #, the BYTE data type in Java is a symbol-Java has no symbol Byte data type. This is why the Sbyte array is used as a parameter using the method of all the processing buffers of the J # runtime.
Fortunately, com.ms.vjsharp.struct namespace contains JavastructMarshalHelper class, which can help you perform array conversions in addition to other features. The CompressString function calls the ConvertTobyTearRay method to convert the string into a symbolic array. In order to get the actual compression bit, I just keep calling Deflater.deflate until deflater.finished returns to indicate that all input data has been consumed. I use Java.io.byteArrayoutputStream's instance to collect the generated data in the compressed cycle. As a general rule, the Java type is processed in C #, it is best to use the JDK class. It is to avoid the best way to convert arrays between Sbyte and Byte. The code for extracting the string looks very similar to the code used to compress. This time, create an instance of a java.util.zip.inflater class and call the setInput method, and incorporate compressed data. The decompression cycle is constantly calling inflater.inflate until INFLATE.FINISHED has become true, indicating that all input data has been decompressed. Finally, call JavastructMarshalHelper.convertTString to convert unsigned byte arrays to strings returned by the function.
CSZIPLL sample application (LL representative low level) Creates a long string and compresses it to approximately half. You can use these functions to complete some work, for example, write SOAP extensions to reduce the network bandwidth required for Web services.
Back to top
Other attractions of J #
Although this paper focuses on how to handle the ZIP file, the principle can also be applied to the J # runtime providing other areas that cannot be obtained from the .NET Framework standard program.
Since J # provides developers to migrate their Visual J projects to the .NET Framework, J # also implements a lot of Visual J features, such as J / Direct ?. J / Direct technology allows the Java language program to call this unit Windows code. Like Visual J , the com.ms.win32 namespace in J # provides access to most Windows API functions, data types, and constants.
The USER32, KERNEL32 and GDI32 classes include the core of the Win32? API function. These constants are defined in an interface called WinX (where X is the first letter of constant) is a static field. For example, the SW_SHOW flag of the showWindow API can be found in the com.ms.win32.wins interface.
In order to make the interface conform to CLS, it shall not contain a field, and the com.ms.win32.winx interface cannot pass the test. Because C # does not allow you to use fields in the interface, both IntelliSense and C # compilers do not see these constants, but you can still use reflection to access these fields as follows:
Private int getWin32intconstant (String name)
{
System.Reflection.Assembly asm =
System.Reflection.Assembly.getassembly (TypeOf (com.ms.win32.wina);
TYPE T = asm.gettype ("com.ms.win32.win" char.tolower (name [0]),
True);
System.Reflection.fieldInfo info = t.Getfield (name); Return Int.Parse (Info.getValue (NULL) .tostring ());
}
Use this technology to retrieve the Windows API constant speed, so you should be careful when using this method. Another problem is that since the constant is less resolved during compilation, whenever you spell them, it will get a runtime error. In any case, most of the Windows APIs can save a lot of work in the .NET program. For example, the Sharpzip sample program displays the system icon associated with the extension of each file. To this end, the code calls the SHGETFILEINFO API defined in the com.ms.win32.shell32 interface to obtain the handle of the icon (see Figure 6).
Note that when you create a System.drawing.icon object from your handle, the new ICON will do not have the handle. This means that you must release the associated resource by calling the Destroyicon API. Since I don't want to store the icon handle during the entire survival of the ICON object, I chose to create a copy of the generated Object.icon by using the replication constructor on its handle.
Although com.ms.win32 namespace is very huge, you should know that it does not contain each Windows API function and data structure. For example, a significant negligence of the com.ms.win32.shell32 interface is the SHBROWSEFORFOLDER API, which allows us to display the Browse for Folder dialog without using the Microsoft Shell Controls and Automation COM library.
Please also note that the processing callback is a bit complicated, which is due to the Java language does not support commission. For each callback type, an abstract class for defining a function prototype is provided. You must derive from this class to implement the code for processing the callback, and then call an instance of the class to the API (see Figure 7). Another smaller difficulty associated with the Java language is that the parameters passed according to the reference are declared as array, but this only affects the code that calls these functions, without affecting the basic function.
Finally, some API calls conversion are very poor. An example is Waveoutopen (defined in the WinMM class). DWCallback parameters are used in C to deliver event handles, window handles, thread IDs, or callback functions, depending on the value of the FDWOPEN parameter. Since the J / Direct package declares the dwcallback parameter as int32, and does not call the callback (delegate) TypeCast to INT32, other notification mechanisms must be used, for example, an event handle, a window handle or a thread ID.
In the core J # package, there are other interesting things. For example, Java.math.BigDecimal and Java.math.Bigintegers classes allow you to manipulate any big numbers, which may be very useful when you write applications to handle encryption algorithms or scientific calculations.
The CSMATH sample project shows how to use Java.math.BigDecimal, calculate the PI with any number of numbers after the decimal point through the formula of Machin. In order to read the code more readily, I wrapped Java.math.BigDecimal in my own BigDecimal class, and defined the most common operator.
Back to top
Application deployment
Application using this technology requires the J # run library and .NET Framework on the target computer. Just like .NET Framework, Microsoft provides a reassient package that can be deployed with an application installer. Microsoft has indicated that J # will continue to support the desktop operating system. However, there is no support for .NET Compact Framework in the current J #, so you cannot apply the technology described in this article to applications for smart devices. The operation of copying the assembly to a local project directory will be invalid because the J # runtime assembly is extremely dependent on the machine call. However, you can take advantage of the J # run library for web applications that use mobile web controls.
Back to top
summary
The J # Run library contains many useful classes that can be used in other languages in .NET Framework. Some classes allow you to handle the ZIP file, perform high-precision mathematical calculations or call the Windows API. Although most of the function can be obtained by using a third-party library, the J # Run field is fully supported by Microsoft and is free!
For related articles, see: Java 911: Parlez-Vous J / Direct?