Javaでファイルの内容を読み取るN個の方法

序文

java 私が最初に連絡した  とき、物事のFile相対パス、つまり参照として使用するディレクトリについて混乱してい  ました。

IOモデルの発展に伴い、Javaの1.7の  nio使用  PathPaths 及び  Files その上には、IO操作を容易にします。

ClassLoaderclass 文件 ioの 取得に使用しましたが、ファイルioの取得にも使用できるため、ファイルの内容を読み取ることができます。

この記事のデザインコンテンツ

  • File、ZipFile、JarFileは、相対パスと絶対パスファイルの内容を読み取ります。
  • System.getProperty( "user.dir")の由来は?
  • パス、パス、ファイルはファイルの内容を読み取ります。
  • クラスローダーは、ファイルコンテンツClass.getResourceAsStreamおよびClassLoader.getResourceAsStreamを取得します。
  • クラスローダーの親の委譲モデルを紹介し、コードで対応する読み込みロジックを見つけます。

<font color = red>コードはMac 10.15.4JDK 1.8に基づいてい  ます。</フォント>

ファイルに基づいてファイルのコンテンツを取得する

絶対パスのコンテンツの取得は比較的簡単で、ファイルioを直接取得し、ツールクラスを使用してファイルのコンテンツを読み取ります。

絶対パスファイルの内容を取得する

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)); 

JarFileのコンテンツを取得する

JarFile 継承は  ZipFile 、jarパッケージのコンテンツを取得するために使用されます。たとえば、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); // 工具类是 hutool System.out.println(IoUtil.read(inputStream, StandardCharsets.UTF_8)); IoUtil.close(inputStream); 

相対パスのコンテンツを取得する

File.getAbsolutePath ソースコードを見ると、相対パスが実際に前にステッチされていることがわかります  System.getProperty("user.dir")

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

私たちがそれを理解する限り  System.getProperty("user.dir")、問題は解決されます。Javaのシステムプロパティは  で説明し  user.dir 、ユーザーの作業ディレクトリ。

画像-20200418232813977

<font color = red>ユーザーの作業ディレクトリは何ですか?これは、javaコマンドが実行されるディレクトリです。</ font>そのディレクトリでコマンドを実行すると、usr.dirがjava仮想マシンによってコマンドを実行するためのパスとして割り当てられます。/Users/zhangpanqin/github/fly-java/test コンパイルしたclass ファイルディレクトリで  実行し  ます。-cp クラスパスパスを指定します。

image-20200418233359327

nio読み取りファイルの内容

Path 類推して使用できます  File 。そして、ツールが  Paths 利用できる  PathFiles だけでなく、ファイルを操作するためのCRUDのAPIを豊富に提供して  Path

絶対パスのコンテンツを取得する

@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)); } 

相対パスのコンテンツを取得する

Paths 相対パスを取得するときに、パスが/ 開始されません  また、System.getProperty("user.dir") パスに対する相対としても理解でき  ます。

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

画像-20200419001203097

ClassLoaderに基づいてファイルコンテンツを取得する

ClassLoader.getResourceAsStream

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

コードから、メインロジックがまだ集中していることがわかり  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; } 

上記のコードのロジックは、よく耳にするもの  双亲委派机制です。してみましょう  父类加载 リソースをロードするために、そして自分が探してそこに見つけることができません。类加载器单独讲

クラスローダーはリソースを読み取って読み取り、最初にそれが担当するパスから検索します。たとえば、アプリケーションクラスローダーは   リソースの検索をsun.misc.Launcher.AppClassLoader#AppClassLoader 担当し  classpathます。リソースを読み取るクラスローダーの 利点File と  Path欠点は何  ですか?たとえばjar 、リソースの1つを取得したい  場合、パスを使用するのはより面倒ですClassLoaderは、責任のあるパスから見つけることも、jarパッケージに見つけることもできます。

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

上記の印刷結果

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

パスも取得できます inputstream

@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)); } 

上記の結果は次のとおりです。

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

Class.getResourceAsStream

Class.getResourceAsStreamClassLoader ロードリソースは 実際にはと呼ばれ  ますが、現在のクラスが配置されているパッケージからの相対パスにパスが追加されます。

たとえば

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

見つかった実際のリソースは  com.fly.study.java.classloader.nameです。現在のクラスが配置されているパッケージのリソースを基準にします。

 

クラスローダー

クラスローダーについてよく耳にします  双亲委派模型

img

これらのクラスが読み込まれた場所はどこにありますか?

启动类加载器 ソースコードがJavaコードに実装されていない場合、ソースコードは表示されません。

sun.misc.Launcherクラスは、私たちが知っている  扩展类加载器 sun.misc.Launcher.ExtClassLoader と  应用类加载器 sun.misc.Launcher.AppClassLoader 。

java.lang.ClassLoader#getSystemClassLoader コードを見ると、実際のアプリケーションクラスローダーが返されます。

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(); } } } 

コードテストを実行すると、アプリケーションクラスローダーが返されます。

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

これらの3つのクラスローダーは、異なるパスでクラスをロードする責任があります。

ブートクラスローダーの紹介

启动类加载器 BootClassLoaderSystem.getProperty("sun.boot.class.path") クラスのロードを 担当します。それは次のカテゴリーです。

${JAVA_HOME}/jre/lib/*.jar そして  ${JAVA_HOME}/jre/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()); }); } 

拡張クラスローダー

扩展类加载器 sun.misc.Launcher.ExtClassLoader 読み込み  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

アプリケーションクラスローダー

应用类加载器 sun.misc.Launcher.AppClassLoader 読み込み中 System.getProperty("java.class.path");

# -cp 指定 classpath 路径,多个路径可以使用 : 分开(linux 下为 :,window 下为 ;),
java -cp /Users/zhangpanqin/github/fly-java/target/classes com.fly.study.java.classloader.Test2 

 

おすすめ

転載: www.cnblogs.com/app7899/p/12732593.html