本人入手写 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-LeHu…
关注公众号:一无是处的钻研僧,理解更多计算机(Java、Python、计算机系统根底、算法与数据结构)常识。