challenge データの圧縮と展開

データを圧縮するcompress、展開するdecompressという関数やメソッドなどを書いてください。データはバイト列でもストリームでもそれ以外の形式でもOKです。

圧縮形式は問いませんが、できるだけ一般的なフォーマット(zip,lzhなど)でお願いします。

また、標準以外のライブラリを使う場合には出典の記載をお願いします。

「○○でも実用的な圧縮/展開プログラムがかけるんだぞ!」というのを、ぜひ示してください。

Posted feedbacks - Scala

 java.util.zipパッケージを使って書いてみました。

 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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import    java.io.{File, BufferedInputStream, BufferedOutputStream, FileInputStream, FileOutputStream, InputStream, OutputStream}
import    java.util.zip.{ZipEntry, ZipInputStream, ZipOutputStream}
import    scala.collection.mutable.HashSet

object Zip {
    def compress(s:String, d:String):Unit =
        (new File(s)) match {
            case f if !f.exists => throw new IllegalArgumentException("no such file.")
            case f => {
                val    o:ZipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(d)))
                val    c:HashSet[File] = new HashSet
                val    b:Array[Byte] = new Array(2048)
                def output(i:InputStream):Unit = i.read(b) match {
                        case -1 => i.close
                        case l => {
                            o.write(b, 0, l)
                            output(i)
                        }
                    }
                def addEntry(p:String, w:Option[(InputStream)=>Unit]):Unit = {
                    o.putNextEntry(new ZipEntry(p))
                    if (w != None) (w.get)(new BufferedInputStream(new FileInputStream(p)))
                    o.closeEntry
                }
                def addDirectory(f:File):Unit =
                    if (f != null) {
                        addDirectory(f.getParentFile)
                        if (!c.contains(f)) {
                            c += f
                            addEntry(f.getPath.replaceAll("\\\\", "/").replaceFirst("/?$", "/"), None)
                        }
                    }
                def loop(f:File):Unit =
                    if (f.isFile)
                        addEntry(f.getPath.replaceAll("\\\\", "/"), Some(output _))
                    else {
                        addDirectory(f)
                        f.listFiles.foreach(loop _)
                    }
                if (f.isFile) addDirectory(f.getParentFile)
                loop(f)
                o.close
            }
        }
    def decompress(s:String):Unit =
        (new File(s)) match {
            case f if !f.exists => throw new IllegalArgumentException("no such file.")
            case f => {
                val    i:ZipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(f)))
                val    b:Array[Byte] = new Array(2048)
                def output(o:OutputStream):Unit = i.read(b) match {
                        case -1 => o.close
                        case l => {
                            o.write(b, 0, l)
                            output(o)
                        }
                    }
                def loop:Unit = {
                    val    e:ZipEntry = i.getNextEntry
                    if (e == null)
                        i.close
                    else {
                        if (e.isDirectory)
                            (new File(e.getName)).mkdirs
                        else {
                            val    f:File = new File(e.getName)
                            if (f.getParentFile != null && !f.exists) f.getParentFile.mkdirs
                            output(new BufferedOutputStream(new FileOutputStream(f)))
                        }
                        i.closeEntry
                        loop
                    }
                }
                loop
            }
        }
}

object Compress {
    import    Zip._
    def main(args:Array[String]):Unit =
        try {
            args.size match {
                case 2 => args.first match {
                        case "-d" => decompress(args.last)
                        case _ => compress(args.first, args.last)
                    }
                case _ => throw new IllegalArgumentException("invalid option.")
            }
        } catch {
            case e:IllegalArgumentException => println("usage: Compress {-d SOURCE | SOURCE DSTINATION}")
            case e => e.printStackTrace
        }
}

Index

Feed

Other

Link

Pathtraq

loading...