自己动手写ls命令——Java版
自己动手写ls命令——Java版
介绍
在前面的文章Linux命令系列之ls——原来最简单的ls这么复杂当中,我们仔细的介绍了关于ls命令的使用和输出结果,在本篇文章当中我们用Java代码自己实现ls命令,更加深入的了解ls命令。
代码实现
文件操作的基本原理
如果我们使用Java实现一个简单的ls命令其实并不难,因为Java已经给我们提供了一些比较方便和文件系统相关的api了,困难的是理解api是在做什么事儿!
事实上这些api都是操作系统给我们提供的,然后Java进行了一些列的封装,将这些操作给我们进行提供,我们仔细来看一下封装的层次,首先操作系统会给我们提供很多系统调用用于和设备(磁盘、CPU)进行交互,比如说和文件的交互就是读写数据,当然我们的Java程序也需要这些操作,因此JVM也需要给我们提供这些操作,因此JVM就对系统调用进行了一系列的封装,在Java当中具体的形式就是用native修饰的方法。
如果你是一个比较有经验Java程序员那么一定见过Java当中的native
方法,这些方法都是Java给我们封装的底层接口,比如说在FileInputStream
当中有一个read
方法,这个方法就是读取文件当中的内容,我们看一下这个方法是如何实现的:
public int read() throws IOException {
return read0();
}
这里让大家的感受更加深入一点,我在这里贴一张FileInputStream
的源代码图片:
从上面的图看当我们调用FileInputStream
方法的时候确实调用了native方法。我们再来看一些与文件操作相关的api,他们也是使用Java给我们封装的native方法实现的。
上面主要谈了一些基本的文件操作过程的原理,简要说明了Java将很多系统操作封装成native方法供我们调用,现在我们来看看要想实现ls命令,我们需要哪些api。
查看一个目录下面有哪些文件和目录
在Java当中给我们提供了一个类File
,我们可以使用这个类去得到一个目录下面有哪些文件和目录。
public void fileTest() {
File file = new File("./");
// file.listFiles() 将当前 file 对应的目录下所有的文件和目录都得到
for (File listFile : file.listFiles()) {
System.out.println(listFile.getName()); // 将文件或者目录的名字打印
}
查看文件和目录的元数据
在Java当中给我们提供了一个工具类查看文件的一些元信息(metadata),比如说文件的uid(用户id)、gid(用户组id)、文件的大小和文件的链接数目(nlink)。
Path path = Paths.get(".");
System.out.println(Files.getAttribute(path, "unix:dev")); // 打印存储当前目录数据的设备的设备id
System.out.println(Files.getAttribute(path, "unix:ino")); // 打印存储当前目录数据inode号
System.out.println(Files.getAttribute(path, "unix:mode"));// 打印存储当前目录数据的mode数据 这个数据主要用于表示文件的类型
System.out.println(Files.getAttribute(path, "unix:uid")); // 打印存储当前目录所属用户的用户id
System.out.println(Files.getAttribute(path, "unix:gid")); // 打印存储当前目录所属组的组id
System.out.println(Files.getAttribute(path, "unix:size"));// 打印存储当前目录数据所占的空间大小
System.out.println(Files.getAttribute(path, "unix:nlink"));// 打印存储当前目录数据的链接数
除了上面的方式,我们还可以使用下面的方式去得到文件的元数据:
public void attrTest02() throws IOException {
Path path = Paths.get("."); // 传入的参数就是文件或者目录的路径 这个传入的就是当前目录
PosixFileAttributes attr = Files.readAttributes(path, PosixFileAttributes.class, NOFOLLOW_LINKS);
System.out.println(attr.owner()); // 打印用户名
System.out.println(attr.group()); // 打印用户组名
System.out.println(attr.isRegularFile()); // 是不是一般文件
System.out.println(attr.isSymbolicLink()); // 是不是一个符号链接
System.out.println(attr.isDirectory()); // 是否是目录
System.out.println(attr.isOther()); //其他类型
System.out.println(attr.permissions()); // 打印文件的权限 是否可读 可写 可执行
System.out.println(attr.lastAccessTime()); // 上一次访问时间
System.out.println(attr.creationTime()); // 创建时间
System.out.println(attr.lastModifiedTime()); // 上一次修改时间
System.out.println(attr.fileKey()); // 打印文件其他相关参数 主要是设备id和inode编号
System.out.println(attr.size()); // 文件的大小
}
root // 这里是用户名
root // 这里是用户组名
false
false
true
false
[GROUP_READ, OTHERS_EXECUTE, OWNER_WRITE, OWNER_EXECUTE, OTHERS_READ, OWNER_READ, GROUP_EXECUTE]
2022-10-09T18:08:47.791072133Z
2022-10-09T13:10:51Z
2022-10-09T18:08:23.746949182Z
(dev=1000012,ino=16176823)
192
文件权限
在Java当中给我们提供了一个类表示文件的9中权限(文件的作者的读写执行,作者所在组的读写执行,和其他人的读写执行,一共九种权限):
package java.nio.file.attribute;
public enum PosixFilePermission {
/**
* Read permission, owner. 作者读权限
*/
OWNER_READ,
/**
* Write permission, owner. 作者写权限
*/
OWNER_WRITE,
/**
* Execute/search permission, owner. 作者的执行权限
*/
OWNER_EXECUTE,
/**
* Read permission, group. 作者所在组的读权限
*/
GROUP_READ,
/**
* Write permission, group.作者所在组的写权限
*/
GROUP_WRITE,
/**
* Execute/search permission, group.
*/
GROUP_EXECUTE,
/**
* Read permission, others. 其他人读权限
*/
OTHERS_READ,
/**
* Write permission, others. 其他人写权限
*/
OTHERS_WRITE,
/**
* Execute/search permission, others. 其他人执行权限
*/
OTHERS_EXECUTE;
}
在上面查看文件或者目录的元数据的时候我们已经得到的文件的所有权限信息:
System.out.println(attr.permissions());
//[GROUP_READ, OTHERS_EXECUTE, OWNER_WRITE, OWNER_EXECUTE, OTHERS_READ, OWNER_READ, GROUP_EXECUTE]
函数返回的是一个集合set
,里面存放的就是文件的各种权限的信息,比如在我们的例子当中我们可以看到,有组读,其他人执行,作者自己写,作者执行,其他人读,作者读权限,如果我们想判断某种权限,只需要看看集合当中是否包含即可。
完整代码实现
在上面我们已经谈到了所有的关于实现 ls 命令的细节了,接下来看一下我们的代码实现:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Objects;
import java.util.Set;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
public class LS {
public static boolean hasRight(Set<PosixFilePermission> set, PosixFilePermission
permission) {
return set.contains(permission);
}
public static void echoCharacter(Set<PosixFilePermission> set) {
// user
if (hasRight(set, PosixFilePermission.OWNER_READ))
System.out.print('r');
else
System.out.print('-');
if (hasRight(set, PosixFilePermission.OWNER_WRITE))
System.out.print('w');
else
System.out.print('-');
if (hasRight(set, PosixFilePermission.OWNER_EXECUTE))
System.out.print('x');
else
System.out.print('-');
// group
if (hasRight(set, PosixFilePermission.GROUP_READ))
System.out.print('r');
else
System.out.print('-');
if (hasRight(set, PosixFilePermission.GROUP_WRITE))
System.out.print('w');
else
System.out.print('-');
if (hasRight(set, PosixFilePermission.GROUP_EXECUTE))
System.out.print('x');
else
System.out.print('-');
// others
if (hasRight(set, PosixFilePermission.OTHERS_READ))
System.out.print('r');
else
System.out.print('-');
if (hasRight(set, PosixFilePermission.OTHERS_WRITE))
System.out.print('w');
else
System.out.print('-');
if (hasRight(set, PosixFilePermission.OTHERS_EXECUTE))
System.out.print('x');
else
System.out.print('-');
}
public static void echoType(PosixFileAttributes attributes) {
if (attributes.isDirectory())
System.out.print('d');
else if (attributes.isRegularFile())
System.out.print('-');
else if (attributes.isSymbolicLink())
System.out.print('l');
else
System.out.print('o');
}
public static void echoFileInformation(String args) throws IOException {
Path path = Paths.get(args);
PosixFileAttributes attributes = Files.readAttributes(path, PosixFileAttributes.class, NOFOLLOW_LINKS);
echoType(attributes);
echoCharacter(attributes.permissions());
System.out.printf("\t%-2d", Files.getAttribute(path, "unix:nlink"));
System.out.print("\t" + attributes.owner().getName());
System.out.print("\t" + attributes.group().getName());
System.out.printf("\t%-5d", attributes.size());
System.out.printf("\t %10s", attributes.lastAccessTime());
System.out.println("\t" + path.getFileName());
}
public static void main(String[] args) throws IOException {
File file = new File(args[0]);
for (File listFile : Objects.requireNonNull(file.listFiles())) {
echoFileInformation(listFile.toString());
}
}
}
上面的代码很短,如果大家了解了上main所谈到的api的话,就应该很容易理解了。下面我们看看程序的输出结果:
可以看到我们的程序的输出结果和ls命令的输出结果是一样的,只是在时间的表示上有所差别而已,这一点没什么关系。
以上就是本篇文章的所有内容了,我是LeHung,我们下期再见!!!更多精彩内容合集可访问项目:https://github.com/Chang-LeHung/CSCore
关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。
自己动手写ls命令——Java版的更多相关文章
- 自己动手写shell命令之ls -R1fF
ls命令的R參数代表递归的列出全部子目录中的全部文件,1表示每一行仅仅显示一个文件或目录,f表示不排序即输出.F表示在每项的输出的最后依据其文件类型对应的加上*/=>@|字符.通过c语言实现ls ...
- 自己动手写shell命令之ls
linux下ls命令(支持-R參数)的c语言实现: #include <stdio.h> #include <sys/types.h> #include <dirent. ...
- Linux系统编程【3.2】——ls命令优化版和ls -l实现
前情提要 在笔者的上一篇博客Linux系统编程[3.1]--编写ls命令中,实现了初级版的ls命令,但是与原版ls命令相比,还存在着显示格式和无颜色标记的不同.经过笔者近两天的学习,基本解决了这两个问 ...
- 自己动手写shell命令之write
Linux下write命令同意用户跟其它终端上的用户对话.用c语言实现shell命令write.代码例如以下: #include <stdio.h> #include <fcntl. ...
- 自己动手写shell命令之more
unix下more命令的简单实现: #include <stdio.h> #define PAGELEN 24 #define LINELEN 512 int do_more(FILE * ...
- 应用程序初次运行数据库配置小程序(Java版)
应用程序初始化数据库配置小程序 之前写过一个Java版的信息管理系统,但部署系统的时候还需要手动的去配置数据库和导入一些初始化的数据才能让系统运行起来,所以我在想是不是可以写一个小程序在系统初次运行的 ...
- linux系统编程:自己动手写一个ls命令
ls用于列举目录内容,要实现这个功能,毫无疑问,需要读取目录,涉及到两个api: opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列 ...
- [JVM] - 一份<自己动手写Java虚拟机>的测试版
go语言下载 配置GOROOT(一般是自动的),配置GOPATH(如果想自己改的话) 参照<自己动手写Java虚拟机> > 第一章 指令集和解释器 生成了ch01.exe文件 这里还 ...
- [编译] 5、在Linux下搭建安卓APP的开发烧写环境(makefile版)—— 在Linux上用命令行+VIM开发安卓APP
星期三, 19. 九月 2018 02:19上午 - BEAUTIFULZZZZ 0)前言 本文不讨论用IDE和文本编辑器开发的优劣,是基于以下两点考虑去尝试用命令行编译安卓APP的: 了解安卓APP ...
随机推荐
- Stream流中的常用方法foeEach和Stream流中的常用方法filter
延迟方法:返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用.(除了中介方法外,其余方法均为延迟方法) 终结方法:返回值类型不再是Stream接口自身类型的方法,因此不再支持类似Stri ...
- github访问较慢问题初步解决方案
简介 众所周知,github在国内向来都是访问的非常坎坷,不挂代理访问起来非常困难,本文将介绍一种不依赖代理的加快访问的方式,但不一定可行哦,只能说是优化 步骤 1.在搜索框中输入记事本或者notep ...
- linux学习系列--初识Linux系统
### 认识Linux- Linux是一种类UNIX的系统,Unix是1965年在贝尔实验室开发的一个项目,用来开发操作系统- Linux之父-Linus Torvalds在1991年10月5日,他在 ...
- 并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_208 协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么 ...
- 搞定面试官 - MySQL 中你知道如何计算一个索引的长度嘛?
大家好,我是程序员啊粥. 今天给大家分享一个我遇到过的比较少见的面试题,那就是 MySQL 中如何计算一个索引的长度. 说实话,我第一次遇到这个问题的时候想当然的以为索引长度就是我们建表时定义的字段长 ...
- CF708C Centroids(树形DP)
发现变重心就是往重心上割,所以\(\text{up and down}\),一遍统计子树最大\(size\),一遍最优割子树,\(down\),\(up\)出信息,最后\(DFS\)出可行解 #inc ...
- BZOJ1787/Luogu4281: [Ahoi2008]Meet 紧急集合
画画图可知,三点\(lca\)必有两相同,\(a,b,c\)距离为\(dis_a + dis_b + dis_c - dis_{lca(a,b)} - dis_{lca(b,c)} - dis_{lc ...
- rcu stall 导致的hung 记录
synchronize_sched 也会在wait_rcu_gp 的长时间等待导致进入hung ,假设rcu没有及时执行的话, 另外,如果rcu积累到一定程度,内存自然就不足了,可能会oom. rcu ...
- 字节跳动基于ClickHouse优化实践之“多表关联查询”
更多技术交流.求职机会.试用福利,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 相信大家都对大名鼎鼎的ClickHouse有一定的了解了,它强大的数据分析性能让人印象深刻.但在字节大量 ...
- 垃圾收集器 参阅<<深入理解JAVA虚拟机>>
一.新生代 1.Serial收集器 新生代单线程复制算法GC(暂停工作线程)---------- 支持组合老年代Serial odl和CMS 2.ParNew Serial多线程版本 支持组合cms| ...