您的位置:首页 > 理论基础 > 数据结构算法

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 tools 数据结构