tanakahdaのプログラマ手帳

プログラミングとかソフトウェア開発とかの備忘録

SLF4J + Logbackのメモ@Java

pom.xml

        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.5.6</version>
        </dependency>

logback.xml は src/main/resourceに配置

<configuration>
 
    <property name="outputDir" value="/Users/tanakahda/Desktop/App/logs/" />
    <property name="fileName" value="app" />
    <property name="format1" value="%d{yyyy/MM/dd HH:mm:ss.SSS} [%-4p] [%c] %m%n" />
 
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${outputDir}${fileName}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
 
        <encoder>
            <pattern>${format1}</pattern>
        </encoder>
    </appender>
 
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${format1}</pattern>
        </encoder>
    </appender>
 
    <root level="debug">
        <appender-ref ref="FILE" />
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

Java

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class Main {
 
    /** ログ出力クラス */
    private static Logger _log = LoggerFactory.getLogger(Main.class);
 
    public static void main(String[] args) {
 
        _log.info("処理を開始します。");
 
        _log.info("処理を終了しました。");
    }
   

結果:

2024/07/06 00:55:56.363 [INFO] [com.tanakahda.Main] 処理を開始します。
2024/07/06 00:55:57.753 [INFO] [com.tanakahda.Main] 処理を終了しました。

入出力でフォルダを再帰的に操作する@Java

Files#walkFileTreeは、ディレクトリ構造を再帰的に走査する。walkFileTreeメソッドの2つ目の引数にFileVisitorインターフェースの実装をセットする。

   /**
    * 指定したディレクトリ配下をすべて削除します。
    * 
    * @param dir
    * @throws IOException
    */
    public static void deleteAll(Path dir) throws IOException {

        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.delete(file);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                if (exc != null) {
                    throw exc;
                }

                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }
   /**
    * srcディレクトリ配下をdestディレクトリへコピーします。
    * 
    * @param src コピー元
    * @param dest コピー先
    * @throws IOException
    */
    public static void copyAll(Path src, Path dest) throws IOException {

        Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Path targetFile = dest.resolve(src.relativize(file));
                    Path parentDir = targetFile.getParent();
                    Files.createDirectories(parentDir);
                    Files.copy(file, targetFile, StandardCopyOption.REPLACE_EXISTING);
                    return FileVisitResult.CONTINUE;
                }
             }
        );
    }

javax.tools.JavaCompilerでコンパイルするときにクラスパスを指定する@Java

javax.tools.JavaCompilerでコンパイルするときに外部jarにクラスパスを通して実行する方法を調査。

javax.tools.JavaCompilerのオプションで"-cp"または"-classpath"を指定する。例えば、以下のように書くことができる。

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
String[] options = new String[]{"-cp", "lib/mylib.jar"};
compiler.run(null, null, null, options, "MyClass.java");

これで、lib/mylib.jarに含まれるクラスをMyClass.javaで利用できる。

Hello JavaFX@JavaFX

Hello.java

package com.tanakahda;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Hello extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("はじめてのJavaFX");
        FXMLLoader loader = new FXMLLoader(getClass().getResource("hello.fxml"));
        HBox root = loader.load();
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

hello.fxml

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<HBox>
    <children>
        <Label text="Hello world!" prefWidth="80.0" style="-fx-alignment:center"/>
    </children>
</HBox>

module-info.java

module JavaFXExamples {
    requires transitive javafx.controls;
    requires transitive javafx.fxml;
    opens com.tanakahda;
    exports com.tanakahda;
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>JavaFXExamples</groupId>
    <artifactId>JavaFXExamples</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <release>17</release>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>17</version>
        </dependency>
        <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-fxml</artifactId>
                <version>17</version>
        </dependency>
    </dependencies>
</project>

jarファイルの中身を別フォルダへ出力@Java

jarファイルの中身を取り出して別フォルダに出力できるかやってみたところ後述のソースコードでできた。 ChatGPT先生に教えてもらった。

下記のプロジェクトを実行可能なjarしたあとに、実行すると自分自身の中身をhogeフォルダへ出力したい。

できた。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


public class Main {

    public static void main(String[] args) {
        new Main().execute();
    }

    public void execute() {
        // jarファイルのパスを取得する
        String jarPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
        // 出力先フォルダのパスを指定する
        String outputFolder = "/Users/tanakahda/Desktop/hoge";
        // jarファイルを開く
        try (JarFile jarFile = new JarFile(jarPath)) {
            // jarファイルに含まれるエントリを列挙する
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                // エントリを取得する
                JarEntry entry = entries.nextElement();
                // エントリの名前を取得する
                String entryName = entry.getName();
                // 出力先ファイルのパスを生成する
                String outputPath = outputFolder + File.separator + entryName;
                // 出力先ファイルの親ディレクトリを作成する
                File parentDir = new File(outputPath).getParentFile();
                if (!parentDir.exists()) {
                    parentDir.mkdirs();
                }
                // エントリがディレクトリでない場合、ファイルとして出力する
                if (!entry.isDirectory()) {
                    // 入力ストリームを開く
                    try (InputStream is = jarFile.getInputStream(entry)) {
                        // 出力ストリームを開く
                        try (OutputStream os = new FileOutputStream(outputPath)) {
                            // バイト配列を用意する
                            byte[] buffer = new byte[1024];
                            int len;
                            // 入力ストリームから読み込み、出力ストリームに書き込む
                            while ((len = is.read(buffer)) > 0) {
                                os.write(buffer, 0, len);
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ProgressMonitorで進捗率を表示する@Java Swing

package tanakahda.apps.progressmonitor;

import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;
import javax.swing.ProgressMonitor;

public class Main {

    public static void main(String[] args) {

        var frame = new JFrame();
        frame.setSize(640, 480);
        frame.setVisible(true);

        // プログレスモニターを表示する
        new Thread(()->{

            ProgressMonitor pm = new ProgressMonitor(
                    frame,
                    "説明メッセージ:どの操作が監視されているかユーザーに示す",
                    "状態を説明する短いメモ",
                    0, 100);
            // 進捗モニターを表示するかどうかを決定するまでの待ち時間を設定します。
            pm.setMillisToDecideToPopup(100);
            // ポップアップが表示されるまでの時間を設定します。
            pm.setMillisToPopup(100);

            for (int i = 0; i <= 100; i++) {
                pm.setNote("進捗率 = " + i + "%");
                // プログレスバーの更新
                pm.setProgress(i);

                // プログレスモニターが可視できるように少し遅延させる
                try {
                    TimeUnit.MILLISECONDS.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            pm.setNote("終了");

        }).start();
    }
}

pipで依存関係の問題を出力する@Python

pip check
spyder 5.1.5 requires pyqt5, which is not installed.
spyder 5.1.5 requires pyqtwebengine, which is not installed.
daal4py 2021.3.0 requires daal, which is not installed.
conda-repo-cli 1.0.4 requires pathlib, which is not installed.
applaunchservices 0.2.1 requires pyobjc, which is not installed.
anaconda-project 0.10.1 requires ruamel-yaml, which is not installed.
thinc-apple-ops 0.1.3 has requirement thinc<9.1.0,>=8.1.0.dev2, but you have thinc 8.0.17.
spacy-transformers 1.1.3 has requirement spacy<4.0.0,>=3.1.3, but you have spacy 3.0.0.
numba 0.54.1 has requirement numpy<1.21,>=1.17, but you have numpy 1.24.1.
ja-ginza 5.1.3 has requirement spacy<3.7.0,>=3.2.0, but you have spacy 3.0.0.
ja-ginza-electra 5.1.2 has requirement spacy<3.5.0,>=3.2.0, but you have spacy 3.0.0.
ja-core-news-lg 3.2.0 has requirement spacy<3.3.0,>=3.2.0, but you have spacy 3.0.0.
ginza 5.1.2 has requirement spacy<3.5.0,>=3.2.0, but you have spacy 3.0.0.
Note: you may need to restart the kernel to use updated packages.