关于linux:自己动手写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-LeHu…

关注公众号:一无是处的钻研僧,理解更多计算机(Java、Python、计算机系统根底、算法与数据结构)常识。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理