09 DirectoryStructure
2015-12-21 21:26
381 查看
前言
这里介绍一下我比较常用的一个生成目录结构的工具, 自己写的..这个也就是前面的存在资源的播客绘制目录结构的工具
记得 当时有这个需求的原因是, 给朋友写一写各个程序模块的功能, 当时 是自己绘制的, 后来想了想, 使用程序实现了一下基本功能
简介
整个程序分为两个步骤1 获取目标目录的元数据信息, 封装起来
2 将目标目录元数据信息拼接成需要展示的形式 [这里 我实现的显示方案有两种]
下面 以图示的形式分析, 详细过程请详见代码
目标目录结构如下
目标目录逻辑结构如下
业务逻辑01获取目标目录元数据
业务逻辑02拼接结果
效果01
效果02
扩展
也就是下面的注释的几个可配置的地方1 getFiles, getFolders : 可以在相应的方法中配置, 自己需要的格式的文件 [比如需要获取.java文件, 在accept方法中配置”file.isFile && file.getName.endsWith(“.java”)”]
2 encapFileObj, encapFolder, getFileString, getFolderString : 配置需要获取该文件的数据, 这里 我只获取的文件的长度, 可以根据自己的需要进行配置
参考代码如下
注意 : 代码为scala代码, 并且依赖于json的相关包
package com.hx.test01 /** * fileName : Test04DirectoryStructure * Created by 970655147 on 2015-10-20 14:19. */ object Test04DirectoryStructure { // 给定一个文件夹, 生成器目录结构 // 可配置的地方 : 1. getFiles, 2. getFolders, 3. encapFileObj, 4. encapFolder, 5. getFileString, 6. getFolderString def main(args :Array[String]): Unit = { val start = System.currentTimeMillis() val folder = new File("C:\\Users\\970655147\\Desktop\\tmp\\directoryStructure") val res = new JSONArray() val isAppendCRLFWhileNoFile = true generateDirectorStructure(folder, res) // println(res.toString ) val spent01 = System.currentTimeMillis() - start val sb :StringBuilder = new StringBuilder() // drawIt(res, 0, ArrayBuffer[Int](), sb, isAppendCRLFWhileNoFile) drawItWithoutSoManyVerticalLines(res, 0, sb, isAppendCRLFWhileNoFile) val spent02 = System.currentTimeMillis() - start - spent01 // println(res.toString(4) ) // println(sb.toString ) Tools.save(sb.toString, Tools.getTmpPath(17, Tools.TXT) ) println("files : " + fileNum + ", folder : " + folderNum + ", size " + getLengthString(size, Tools.MB) ) val spent03 = System.currentTimeMillis() - start - spent01 - spent02 println("gene dirStructure : " + spent01 + " ms ...") println("calc spent : " + spent02 + " ms ...") println("print spent : " + spent03 + " ms ...") } // 常量 val NAME = "name" val TYPE = "type" val FILE = "file" val DIR = "dir" val EMPTY = "NULL" val SIZE = "size" // 统计文件个数, 文件夹个数 var fileNum = 0 var folderNum = 0 var size = 0L // 生成给定目录的目录结构 [递归] // 对于文件获取数据 {type : typeVal, name : nameVal } // 对于目录获取数据 [{type : dir, name : curFolderName }, {... }, {... }, [... ], [... ] ] def generateDirectorStructure(folder :File, res :JSONArray) :Unit = { if(! folder.exists()) { println("please makeSure " + folder.getPath + " does exists ..." ) return } if(folder.isDirectory) { res.add(encapFolder(folder) ) val files = getFiles(folder) for(file <- files) { res.add(encapFileObj(file) ) size += file.length } fileNum += files.length val dirs = getFolders(folder) for(dir <- dirs) { val arr = new JSONArray() generateDirectorStructure(dir, arr ) res.add(arr ) } folderNum += dirs.length } } // 绘制的时候竖线到文件名之间, 显示的"-"的个数 val lengthPerSep = 2 // 绘制给定的目录结构 // 返回当前目绘制占用的行数 def drawIt(res :JSONArray, offset :Int, verticalLines :ArrayBuffer[Int], sb :StringBuilder, isAppendCRLFWhileNoFile :Boolean) :Int = { val meta = res.getJSONObject(0) var rows = 0 var appendedRows = 0 if(equalsIgnoreCase(meta.getString(TYPE), DIR) ) { val folerInfo = getFolderString(meta) append(sb, folerInfo ) appendSeps(sb, lengthPerSep+1) val verticalLineOffset = offset + folerInfo.length + lengthPerSep val newVerticalLines = copyOf(verticalLines) newVerticalLines += verticalLineOffset val folderStart = getFolderStart(res) for(i <- 1 until folderStart) { val file = res.getJSONObject(i) if(i != 1) { append(sb, Tools.CRLF) appendVerticalLine(sb, newVerticalLines) } appendSeps(sb, lengthPerSep) append(sb, getFileString(file) ) } rows += (folderStart - 1) for(i <- folderStart until res.size) { val dir = res.getJSONArray(i) append(sb, Tools.CRLF) appendVerticalLine(sb, newVerticalLines) appendSeps(sb, lengthPerSep) appendedRows = drawIt(dir, (verticalLineOffset + lengthPerSep), copyOf(newVerticalLines), sb, isAppendCRLFWhileNoFile) // 如果此次添加的添加的元素个数大于1个, 则打印一个回车 [方便查看] rows += appendedRows } } if(rows == 0) { appendSeps(sb, lengthPerSep+1) append(sb, EMPTY) } if(isAppendCRLFWhileNoFile) { if(rows - appendedRows > 0) { append(sb, Tools.CRLF) appendVerticalLine(sb, verticalLines) } } rows } // 绘制给定的目录结构 // 返回当前目绘制占用的行数 def drawItWithoutSoManyVerticalLines(res :JSONArray, offset :Int, sb :StringBuilder, isAppendCRLFWhileNoFile :Boolean) :Int = { val meta = res.getJSONObject(0) var rows = 0 var appendedRows = 0 if(equalsIgnoreCase(meta.getString(TYPE), DIR) ) { val folerInfo = getFolderString(meta) append(sb, folerInfo ) appendSeps(sb, lengthPerSep+1) val verticalLineOffset = offset + folerInfo.length + lengthPerSep val folderStart = getFolderStart(res) for(i <- 1 until folderStart) { val file = res.getJSONObject(i) if(i != 1) { append(sb, Tools.CRLF) appendVerticalLine(sb, verticalLineOffset) } appendSeps(sb, lengthPerSep) append(sb, getFileString(file) ) } rows += (folderStart - 1) for(i <- folderStart until res.size) { val dir = res.getJSONArray(i) append(sb, Tools.CRLF) appendVerticalLine(sb, verticalLineOffset) appendSeps(sb, lengthPerSep) appendedRows = drawItWithoutSoManyVerticalLines(dir, (verticalLineOffset + lengthPerSep + 1), sb, isAppendCRLFWhileNoFile) // 如果此次添加的添加的元素个数大于1个, 则打印一个回车 [方便查看] rows += appendedRows } } if(rows == 0) { appendSeps(sb, lengthPerSep+1) append(sb, EMPTY) } if(isAppendCRLFWhileNoFile) { if(rows - appendedRows > 0) { append(sb, Tools.CRLF) } } rows } // 获取给定的文件夹的所有一级子文件 private def getFiles(folder :File) :Array[File] = { folder.listFiles(new FileFilter() { def accept (file: File) :Boolean = { file.isFile && !file.getName.contains("线") } }) } // 获取给定的文件夹的所有一级子文件夹 private def getFolders(folder :File) :Array[File] = { folder.listFiles(new FileFilter() { def accept (file: File) :Boolean = { file.isDirectory } }) } // 封装需要获取file的信息 private def encapFileObj(file :File) :JSONObject = { new JSONObject().element(TYPE, FILE).element(NAME, file.getName).element(SIZE, file.length()) } // 封装需要获取文件夹的信息 private def encapFolder(file :File) :JSONObject = { new JSONObject().element(TYPE, DIR).element(NAME, file.getName) } // 获取文件, 文件夹的字符串表示 private def getFolderString(file :JSONObject) :String = { file.getString(NAME) + "[dir]" } private def getFileString(file :JSONObject) :String = { file.getString(NAME) + "[" + getLengthString(file.getLong(SIZE), Tools.KB) + "]" } // 根据文件长度, 获取文件的kb数 def getLengthString(length :Long, dimen :String) :String = { if(equalsIgnoreCase(Tools.BYTE, dimen)) { length + " " + Tools.BYTE } else if(equalsIgnoreCase(Tools.KB, dimen) ) { Tools.getKBytesByBytes(length) + " " + Tools.KB } else if(equalsIgnoreCase(Tools.MB, dimen) ) { Tools.getMBytesByBytes(length) + " " + Tools.MB } else if(equalsIgnoreCase(Tools.GB, dimen) ) { Tools.getGBytesByBytes(length) + " " + Tools.GB } else if(equalsIgnoreCase(Tools.TB, dimen) ) { Tools.getTBytesByBytes(length) + " " + Tools.TB } else { length + " " + Tools.BYTE } } // 判断str01 和str02 是否相等 [忽略大小写] def equalsIgnoreCase(str01 :String, str02 :String) :Boolean = { str01.toUpperCase.equals(str02.toUpperCase) } // folder : [{curInfo }, {file}, {file}, .. [folder], [folder], .. ] // 获取当前文件夹下面的第一个dolder的索引 def getFolderStart(arr: JSONArray) :Int = { for(i <- 1 until arr.size) { val obj = arr.get(i) if(obj.isInstanceOf[JSONArray]) { return i } } arr.size } // 复制给定的数组 def copyOf(src :ArrayBuffer[Int]) :ArrayBuffer[Int] = { val dst = new ArrayBuffer[Int](src.size) dst.insertAll(0, src) dst } // 添加分割符 def appendSeps(sb :StringBuilder, lengthPerSep :Int) :Unit = { for(i <- 0 until lengthPerSep) { sb.append("-") } } // 添加字符 def append(sb :StringBuilder, value :String) :Unit = { sb.append(value) } // 添加分割符 def appendVerticalLine(sb :StringBuilder, offsets :ArrayBuffer[Int]) :Unit = { // for (off <- offsets.scanLeft(0)((first, second) => second - first) ) { var last = 0 for(off <- offsets) { appendOffset(sb, off - last) sb.append("|") last = off } } // 添加分割符 def appendVerticalLine(sb :StringBuilder, offset :Int) :Unit = { appendOffset(sb, offset) sb.append("|") } // 添加偏移的空格 def appendOffset(sb :StringBuilder, offset :Int) :Unit = { for(i <- 0 until offset) { sb.append(" ") } } }
使用效果
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树