challenge tailの実装

'tail'を実装してください。

巨大なファイルでも効率的に動作するようにしてください。

最低限必要な機能は、

  • 行数指定
  • 「-f」パラメータの対応

です。

Posted feedbacks - Scala

 オプションの処理にかなり場所をとられてしまっていますが...。

  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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import    java.io.FileNotFoundException
import    java.io.File
import    java.io.FileInputStream
import    scala.collection.mutable.HashMap

class InvalidArgumentException extends Exception {}

class GetOpt(f:String) {
    var    _params:List[Tuple2[String,Boolean]] = null
    var    _opt:HashMap[Any,Any] = null
    var    _rest:Array[String] = null
    
    _params = f.toList.foldLeft(List[Tuple2[String,Boolean]]()) { (l,c) =>
        c match {
            case ':' => l match {
                case List() => throw new InvalidArgumentException
                case h::r => (h._1,true)::r
            }
            case k => (k.toString,false)::l
        }
    }.reverse
    
    def parse(a:Array[String]):GetOpt = {
        def _parse(o:HashMap[Any,Any],l:List[String]):Tuple2[HashMap[Any,Any],List[String]] = l match {
            case List() => (o,List())
            case h::r => h.toList match {
                case '-'::k => {
                    _params.find { e => e._1 == new String(k.toArray) } match {
                        case Some(Tuple2(_,true)) => {
                            if (r.size == 0) throw new InvalidArgumentException
                            o.update(new String(k.toArray),r.head)
                            _parse(o,r.tail)
                        }
                        case Some(Tuple2(_,false)) => {
                            o.update(new String(k.toArray),true)
                            _parse(o,r)
                        }
                        case _ => throw new InvalidArgumentException
                    }
                }
                case _ => (o,l)
            }
        }
        _parse(new HashMap[Any,Any],a.toList) match {
            case Tuple2(o,r) => { _opt = o; _rest = r.toArray }
        }
        this
    }
    
    def getopt(k:String):Any = _opt.isDefinedAt(k) match {
        case true => _opt.apply(k)
        case _ => false
    }
    
    def rest:Array[String] = _rest
}

class CTail(n:Int,f:Boolean,i:File) {
    
    val    s:FileInputStream = new FileInputStream(i)
    
    def this(o:GetOpt) =this(o.getopt("n") match { case Some(false) => 10; case n => n.asInstanceOf[String].toInt },o.getopt("f").asInstanceOf[Boolean],new File(o.rest.apply(0)))
    
    def tailn:Unit = {
        
        val    BUF_SIZE:Int = 4096
        val    e:Long = i.length
        
        def _tailn(p:Long,n:Int,b:Array[Byte]):Array[Byte] = {
            var    t:Array[Byte] = null
            var    l:Int = n
            (p > BUF_SIZE) match {
                case true => {
                    t = new Array[Byte](BUF_SIZE)
                    s.getChannel.position(p - BUF_SIZE)
                    s.read(t,0,BUF_SIZE)
                }
                case _ => {
                    t = new Array[Byte](p.toInt)
                    s.read(t,0,p.toInt)
                }
            }
            t = t.reverse.takeWhile { c => if (c == '\n') l = l - 1; (l > 0) }.reverse
            ((p <= BUF_SIZE) || (l == 0)) match {
                case true => t ++ b
                case _ => _tailn(p - BUF_SIZE, l, t ++ b)
            }
        }
        
        print(new String(_tailn(e, n, new Array[Byte](0))))
        s.getChannel.position(e)
    }
    
    def tailf:Unit = {
        def _tailf(b:List[Byte]):List[Byte] = {
            val    c:Int = s.read
            (c >= 0) match {
                case true => _tailf(b + c.toByte)
                case _ => b
            }
        }
        print(new String(_tailf(List[Byte]()).toArray))
        Thread.sleep(100)
        tailf
    }
    
    def tail:CTail = {
        tailn
        if (f) tailf
        this
    }
    
    def close:Unit = s.close
}

object Tail {
    def main(args:Array[String]):Unit = {
        try {
            val    o:GetOpt = new GetOpt("n:f").parse(args)
            (new CTail(o)).tail.close
        } catch {
            case e:InvalidArgumentException => println("usage: scala Tail [-n <number of lines>] [-f] file")
            case e:FileNotFoundException => print("file not found.")
            case e:Exception => e.printStackTrace
        }
    }
}

Index

Feed

Other

Link

Pathtraq

loading...