小言_互联网的博客

C#压缩文件解压文件

353人阅读  评论(0)

C#压缩文件Java解压文件

源起:最近在做项目时遇到C#和java交互文件处理,C#使用 ICSharpCode.SharpZipLib将文件压缩,Java使用java.util.zip解压文件,前提要求java解压时必须使用UTF-8的编码格式,因此也就需要C#压缩文件时使用UTF-8编码(那么不使用会出现什么问题?)

这个问题其实就涉及到了一些编码的问题,常见的我们都知道ASCII、GBK、UTF-8等等。。。

那么为什么会乱码,根本原因就是字节不同导致在解读时产生了不同的解读方式,这里给大家分享一篇文章

https://www.cnblogs.com/flashsun/p/13975316.html(闪客sun)讲述的很详细,有兴趣的话可以了解一下.

回归正题

如果你阅读了上面的文章你应该已经了解了为什么会乱码(默认你们都看过了)

那么我们来看一下如何造成的这种问题先看一下压缩文件的代码

使用C#的ICSharpCode.SharpZipLib库

    /// <summary>
    /// 文件压缩
    /// </summary>
    /// <param name="sourceFilePath">源文件</param>
    /// <param name="destinationZipFilePath">目标路径</param>
    public static void CreateZip(string sourceFilePath, string destinationZipFilePath)
    {
        if (sourceFilePath[sourceFilePath.Length - 1] != System.IO.Path.DirectorySeparatorChar)
            sourceFilePath += System.IO.Path.DirectorySeparatorChar;
        ZipOutputStream zipStream = new ZipOutputStream(File.Create(destinationZipFilePath));
        zipStream.SetLevel(6);  // 压缩级别 0-9
        CreateZipFiles(sourceFilePath, zipStream, sourceFilePath);

        zipStream.Finish();
        zipStream.Close();
    }

    /// <summary>
    /// 递归压缩文件
    /// </summary>
    /// <param name="sourceFilePath"></param>
    /// <param name="zipStream"></param>
    /// <param name="staticFile"></param>
    private static void CreateZipFiles(string sourceFilePath, ZipOutputStream zipStream, string staticFile)
    {
        Crc32 crc = new Crc32();
        string[] filesArray = Directory.GetFileSystemEntries(sourceFilePath);
        foreach (string file in filesArray)
        {
            if (Directory.Exists(file))                     //如果当前是文件夹,递归
            {
                CreateZipFiles(file, zipStream, staticFile);
            }

            else                                            //如果是文件,开始压缩
            {
                FileStream fileStream = File.OpenRead(file);

                byte[] buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, buffer.Length);
                string tempFile = file.Substring(staticFile.LastIndexOf("\\") + 1);

                ZipEntry entry = new ZipEntry(tempFile);
                entry.DateTime = DateTime.Now;
                entry.Size = fileStream.Length;
                fileStream.Close();
                crc.Reset();
                crc.Update(buffer);
                entry.Crc = crc.Value;
                zipStream.PutNextEntry(entry);

                zipStream.Write(buffer, 0, buffer.Length);
            }
        }
    }

下面再看一下Java 解压文件的代码

使用的是java.util.zip类库

public static void main(String[] args) {
   
    long startTime = System.currentTimeMillis();
    try {
   
        ZipInputStream Zin = new ZipInputStream(new FileInputStream("输入源zip路径"));//输入源zip路径
        BufferedInputStream Bin = new BufferedInputStream(Zin);
        String Parent = "输出路径"; //输出路径(文件夹目录)
        File Fout = null;
        ZipEntry entry;
        try {
   
            while ((entry = Zin.getNextEntry()) != null ) {
   
                if (!entry.isDirectory()) {
   
                    Fout = new File(Parent, entry.getName());
                    if (!Fout.exists()) {
   
                        (new File(Fout.getParent())).mkdirs();
                    }
                    FileOutputStream out = new FileOutputStream(Fout);
                    BufferedOutputStream Bout = new BufferedOutputStream(out);
                    int b;
                    while ((b = Bin.read()) != -1) {
   
                        Bout.write(b);
                    }
                    Bout.close();
                    out.close();
                    System.out.println(Fout + "解压成功");
                }
            }
            Bin.close();
            Zin.close();
        } catch (IOException e) {
   
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } catch (FileNotFoundException e) {
   
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    long endTime = System.currentTimeMillis();
    System.out.println("耗费时间: " + (endTime - startTime) + " ms");
}

使用以上的代码压缩解压后Java报错(前提是要解压缩的文件中包含中文)

Exception in thread “main” java.lang.IllegalArgumentException: malformed input off : 1, length : 1
at java.base/java.lang.StringCoding.throwMalformed(StringCoding.java:698)
at java.base/java.lang.StringCoding.decodeUTF8_0(StringCoding.java:781)
at java.base/java.lang.StringCoding.newStringUTF8NoRepl(StringCoding.java:978)
at java.base/java.lang.System 2. n e w S t r i n g U T F 8 N o R e p l ( S y s t e m . j a v a : 2267 ) a t j a v a . b a s e / j a v a . u t i l . z i p . Z i p C o d e r 2.newStringUTF8NoRepl(System.java:2267) at java.base/java.util.zip.ZipCoder 2.newStringUTF8NoRepl(System.java:2267)atjava.base/java.util.zip.ZipCoderUTF8ZipCoder.toString(ZipCoder.java:208)
at java.base/java.util.zip.ZipCoder.toString(ZipCoder.java:66)
at java.base/java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:302)
at java.base/java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:124)
at demo.CopyOfMyzipDecompressing.main(CopyOfMyzipDecompressing.java:22)
Caused by: java.nio.charset.MalformedInputException: Input length = 1
… 9 more

出现报错原因是:C#默认编码为GBK而java.util.zip默认是UTF-8编码所以在导致解压报错,那么要解决问题根本原因在于让C#解压是使用UTF-8编码

找到问题原因了,那么我们只要解决压缩的时候把编码设置为UTF-8就可以了

ICSharpCode.SharpZipLib库没有很明显的设置编码的方法,比如java.util.zip库就很明显的提供了两个方法可以设置编码格式,

而C#类库中就没有这种方法

没办法现在要么网上找资料,要么去官网查文档或者看源码

当然本着学习的精神我们直接找到源码看一下,通过上面的代码我们可以发现主要就是 PutNextEntry在做压缩这件事情

这里不带大家每行代码去看了 直接给出关键的位置ConvertToArray

可以看到这里使用的编码方式就是ZipConstants.DefaultCodePage这个属性,那么解决方案就有了 我们直接改掉这个属性就可以了

       Encoding gbk = Encoding.GetEncoding("UTF-8");
        ZipConstants.DefaultCodePage = gbk.CodePage;

试一下发现果然解决问题了,但是在最新的dll中这个属性已经过时了,那是不是有其他方法?

再回去看我们可以发现ConvertToArray有两个方法重载

这里竟然有UTF-8的编码,看来作者已经考虑到了问题并提供了新的方案,所以这里这要让flags传值就可以了最后的代码是

    /// <summary>
    /// 文件压缩
    /// </summary>
    /// <param name="sourceFilePath">源文件</param>
    /// <param name="destinationZipFilePath">目标路径</param>
    public static void CreateZip(string sourceFilePath, string destinationZipFilePath)
    {
        if (sourceFilePath[sourceFilePath.Length - 1] != System.IO.Path.DirectorySeparatorChar)
            sourceFilePath += System.IO.Path.DirectorySeparatorChar;
        ZipOutputStream zipStream = new ZipOutputStream(File.Create(destinationZipFilePath));
        zipStream.SetLevel(6);  // 压缩级别 0-9
        CreateZipFiles(sourceFilePath, zipStream, sourceFilePath);

        zipStream.Finish();
        zipStream.Close();
    }

    /// <summary>
    /// 递归压缩文件
    /// </summary>
    /// <param name="sourceFilePath"></param>
    /// <param name="zipStream"></param>
    /// <param name="staticFile"></param>
    private static void CreateZipFiles(string sourceFilePath, ZipOutputStream zipStream, string staticFile)
    {
        Crc32 crc = new Crc32();
        string[] filesArray = Directory.GetFileSystemEntries(sourceFilePath);
        foreach (string file in filesArray)
        {
            if (Directory.Exists(file))                     //如果当前是文件夹,递归
            {
                CreateZipFiles(file, zipStream, staticFile);
            }

            else                                            //如果是文件,开始压缩
            {
                FileStream fileStream = File.OpenRead(file);

                byte[] buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, buffer.Length);
                string tempFile = file.Substring(staticFile.LastIndexOf("\\") + 1);

                ZipEntry entry = new ZipEntry(tempFile);
                entry.DateTime = DateTime.Now;
                entry.Size = fileStream.Length;
                entry.Flags = 2048;
                fileStream.Close();
                crc.Reset();
                crc.Update(buffer);
                entry.Crc = crc.Value;
                zipStream.PutNextEntry(entry);

                zipStream.Write(buffer, 0, buffer.Length);
            }
        }
    }

到此这个问题已经完美解决了,很简单的问题但是从中可以看到自己很多不足之处, 努力吧 打工人!!!


转载:https://blog.csdn.net/qq_38251913/article/details/113859882
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场