n-way to read file content in Java

Preface

When I first contacted java, I was confused about the relative path of a File and which directory to use as a reference.

With the development of io model, nio in java 1.7 uses Path, Paths and Files to facilitate the operation of io.

ClassLoader is used to get the io of the class file, and we can also use it to get the io of the file, so that we can read the content of the file.

Design content of this paper

  • File, ZipFile and JarFile read the contents of relative path and absolute path files.
  • How does System.getProperty("user.dir") come from.
  • Paths, Path, and Files read the contents of the file.
  • Class loader gets the file content, Class.getResourceAsStream and ClassLoader.getResourceAsStream.
  • This paper introduces the parent delegation model of classloader and finds the corresponding loading logic in the code.

The code is based on Mac 10.15.4 and JDK 1.8. </font>

Get File content based on File

The content of absolute path is easy to obtain, I / O is obtained directly, and then the content of file is read by tool class.

Get absolute path file content

final File file = new File("/Users/zhangpanqin/github/fly-java/demo.txt");
final byte[] bytes = cn.hutool.core.io.FileUtil.readBytes(file);
System.out.println(new String(bytes, StandardCharsets.UTF_8));

Get content in JarFile

JarFile inherits ZipFile to get the contents of jar package. For example, I want to get the contents of a file in jar.


final File file = new File("/Users/zhangpanqin/github/fly-java/src/main/resources/fastjson-1.2.68.jar");
final JarFile jarFile = new JarFile(file);
final JarEntry jarEntry = jarFile.getJarEntry("META-INF/LICENSE.txt");
final InputStream inputStream = jarFile.getInputStream(jarEntry);
// The tool class is hutool
System.out.println(IoUtil.read(inputStream, StandardCharsets.UTF_8));
IoUtil.close(inputStream);

Get content of relative path

File.getAbsolutePath check the source code and you can see that the relative path actually splices System.getProperty("user.dir") in front of it.

class UnixFileSystem extends FileSystem {
    public String resolve(File f) {
        if (isAbsolute(f)) return f.getPath();
        return resolve(System.getProperty("user.dir"), f.getPath());
    }
}

As long as we know System.getProperty("user.dir"), the problem will be solved. Java System Properties user.dir is the user's working directory.

< font color = Red > what is a user's working directory? Is the directory where the java command is executed. When executing the command in that directory, usr.dir will be assigned as the path to execute the command by the java virtual machine. I run the compiled class file in the / users / zhangpanqin / GitHub / fly java / test directory. -cp specifies the classpath path.

nio read file contents

Path can be used in analogy with File. Then path can be obtained from the tool class Paths, and Files provides a rich api for crud operation File path.

Get absolute path content

@Test
public void run33() throws IOException {
   final Path path = Paths.get("/Users/zhangpanqin/github/fly-java/demo.txt");
   final byte[] bytes = Files.readAllBytes(path);
   System.out.println(new String(bytes,StandardCharsets.UTF_8));
}

Get relative path content

Paths does not start with / when getting relative paths. It can also be understood relative to the System.getProperty("user.dir") path.

public static void main(String[] args) {
    System.out.println(System.getProperty("user.dir"));
    System.out.println(Paths.get("").toAbsolutePath());
}

Get file content based on ClassLoader

ClassLoader.getResourceAsStream

// ClassLoader.getResourceAsStream java 1.8 source code
public InputStream getResourceAsStream(String name) {
    URL url = getResource(name);
    try {
        return url != null ? url.openStream() : null;
    } catch (IOException e) {
        return null;
    }
}

From the code, we can see that the main logic is still focused on getResource.

public URL getResource(String name) {
    URL url;
    if (parent != null) {
        url = parent.getResource(name);
    } else {
        url = getBootstrapResource(name);
    }
    if (url == null) {
        url = findResource(name);
    }
    return url;
}

The logic of the above code is the parent delegation mechanism we often hear about. First let the parent class load to load the resource, and then find it by yourself. Class loader.

Class loader reads and reads resources, and first looks up from the Path it is responsible for. For example, the application class loader sun.misc.launcher.appclassloader is responsible for classpath lookup resources. What are the advantages of ClassLoader reading resources over File and Path? For example, when I want to get resources in a jar, it's more troublesome for you to use the Path. ClassLoader can find them from the responsible Path, or from the jar package.

final URL resource = Test2.class.getClassLoader().getResource("com/alibaba/fastjson/JSONArray.class");
System.out.println(resource);

The above printing results

jar:file:/Users/zhangpanqin/.m2/repository/com/alibaba/fastjson/1.2.62/fastjson-1.2.62.jar!/com/alibaba/fastjson/JSONArray.class

We can also get the inputstream of a path

@Test
public void run222(){
    final InputStream resourceAsStream = Test2.class.getClassLoader().getResourceAsStream("META-INF/maven/com.alibaba/fastjson/pom.properties");
    System.out.println(IoUtil.read(resourceAsStream, StandardCharsets.UTF_8));
}

The results are as follows:

#Generated by Maven
#Mon Oct 07 22:09:36 CST 2019
version=1.2.62
groupId=com.alibaba
artifactId=fastjson

Class.getResourceAsStream

Class.getResourceAsStream also calls ClassLoader to load resources, but it will supplement the path to the path relative to the package where the current class is located.

such as

// com.fly.study.java.classloader.Test2
@Test
public void run555(){
    System.out.println(Test2.class.getResource("name"));
}

The actual resource to find is com.fly.study.java.classloader.name. The resource relative to the package of the current class.

Class loader

We often hear about the parental delegation model for classloaders.

Where can I see these class loads.

The startup class loader is not implemented by java code. We can't see the source code.

In the sun.misc.Launcher class, we know the extension class loader sun.misc.Launcher.ExtClassLoader and application class loader sun.misc.Launcher.AppClassLoader.

Java.lang.classloader ා getsystemclassloader code, the actual returned application class loader.

public static ClassLoader getSystemClassLoader() {
    initSystemClassLoader();
    if (scl == null) {
        return null;
    }
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkClassLoaderPermission(scl, Reflection.getCallerClass());
    }
    return scl;
}
private static synchronized void initSystemClassLoader() {
        if (!sclSet) {
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            if (l != null) {
                Throwable oops = null;
                scl = l.getClassLoader();
            }
        }
}

Run the code test and return the application class loader.

// sun.misc.Launcher$AppClassLoader@18b4aac2
@Test
public void run66(){
	System.out.println(ClassLoader.getSystemClassLoader());
}

These three classloaders are responsible for class loading in different paths.

Introduction to boot class loader

BootClassLoader is responsible for class loading of System.getProperty("sun.boot.class.path"). That is, the following classes.

Loading of ${JAVA_HOME}/jre/lib/*.jar and ${JAVA_HOME}/jre/classes classes classes.

/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/sunrsasign.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/classes
@Test
public void run77() {
    final URLClassPath bootstrapClassPath = Launcher.getBootstrapClassPath();
    final URL[] urLs = bootstrapClassPath.getURLs();
    Stream.of(urLs).forEach(item->{
        System.out.println(item.getFile());
    });
}

extensions class loader

The extension class loader sun.misc.Launcher.ExtClassLoader loads the classes in System.getProperty("java.ext.dirs").

@Test
public void run99() {
    final String property = System.getProperty("java.ext.dirs");
    final String[] split = property.split(":");
    Stream.of(split).forEach(item -> {
        System.out.println(item);
    });
}
/Users/zhangpanqin/Library/Java/Extensions
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext
/Library/Java/Extensions
/Network/Library/Java/Extensions
/System/Library/Java/Extensions
/usr/lib/java

Application class loader

Application class loader sun.misc.Launcher.AppClassLoader loads System.getProperty("java.class.path");

# -cp specifies the classpath path. Multiple paths can be used: separate (linux:, window;),
java -cp /Users/zhangpanqin/github/fly-java/target/classes com.fly.study.java.classloader.Test2 

This article is composed of Zhang Panqin's blog http://www.mflyyou.cn/ A literary creation. It can be reprinted and quoted freely, but it needs to be signed by the author and indicate the source of the article.

If you are reprinted to WeChat official account, please add the author's official account number 2. WeChat official account name: Mflyyou

Tags: Front-end Java JDK github Maven

Posted on Sun, 19 Apr 2020 03:55:54 -0700 by danj