Включение всех jar-файлов в каталог внутри Java classpath

840

Есть ли способ включить все файлы jar в каталог в пути к классам?

Я пытаюсь java -classpath lib/*.jar:. my.package.Program, и он не может найти файлы классов, которые, безусловно, находятся в этих банках. Нужно ли добавлять каждый файл jar в classpath отдельно?

  • 3
    Извините, я никогда не принимал это. Это должно быть сообщество вики. Никогда не использовал один из предоставленных ответов. Я считаю, что я создал сценарий оболочки, который просто просканировал каталог lib / и создал путь к классам путем анализа имен файлов.
  • 0
    В этой новой функции Java есть какая-то ошибка, потому что она не работает, как описано. Я сдался и использовал Ant, чтобы обойти это, как описано в одном из ответов.
Показать ещё 4 комментария
Теги:
command-line
classpath

23 ответа

1017

Используя Java 6 или более позднюю версию, параметр classpath поддерживает подстановочные знаки. Обратите внимание на следующее:

  • Используйте прямые кавычки (")
  • Используйте *, а не *.jar

Windows

java -cp "Test.jar;lib/*" my.package.MainClass

Юникс

java -cp "Test.jar:lib/*" my.package.MainClass

Это похоже на Windows, но использует : вместо ; , Если вы не можете использовать подстановочные знаки, bash допускает следующий синтаксис (где lib - это каталог, содержащий все файлы архива Java):

java -cp $(echo lib/*.jar | tr ' ' ':')

(Обратите внимание, что использование -jar несовместимо с параметром -jar. См. Также: Выполнить файл jar с несколькими библиотеками классов из командной строки)

Понимание подстановочных знаков

Из документа Classpath:

Записи пути класса могут содержать символ подстановочного имени базы данных *, который считается эквивалентным заданию списка всех файлов в каталоге с расширением .jar или .JAR. Например, запись пути к файлу foo/* указывает все файлы JAR в каталоге с именем foo. Элемент classpath, состоящий просто из * расширяется до списка всех файлов jar в текущем каталоге.

Запись пути к классу, содержащая *, не будет соответствовать файлам классов. Чтобы сопоставить оба класса и JAR файлы в одном каталоге foo, используйте foo;foo/* или foo/*;foo. Выбранный порядок определяет, загружаются ли классы и ресурсы в foo перед JAR файлами в foo или наоборот.

Подкаталоги не ищут рекурсивно. Например, foo/* ищет файлы JAR только в foo, а не в foo/bar, foo/baz и т.д.

Порядок, в котором файлы JAR в каталоге перечислены в расширенном пути класса, не указывается и может варьироваться от платформы к платформе и даже от момента к моменту на одном компьютере. Хорошо построенное приложение не должно зависеть от какого-либо конкретного порядка. Если требуется конкретный заказ, файлы JAR могут быть перечислены явно в пути к классу.

Расширение подстановочных знаков выполняется раньше, чем вызов основного метода программы, а не поздно, во время самого процесса загрузки класса. Каждый элемент пути входного класса, содержащий подстановочный знак, заменяется (возможно, пустой) последовательностью элементов, сгенерированных путем перечисления файлов JAR в названном каталоге. Например, если каталог foo содержит a.jar, b.jar и c.jar, то путь класса foo/* разложен в foo/a.jar;foo/b.jar;foo/c.jar и эта строка будет значением системного свойства java.class.path.

Переменная среды CLASSPATH не обрабатывается иначе, чем -classpath командной строки -classpath (или -cp). То есть, во всех этих случаях соблюдаются подстановочные знаки. Тем не менее, групповые маски пути класса не выполняются в заголовке Class-Path jar-manifest.

Примечание: из-за известной ошибки в java 8, примеры Windows должны использовать обратную косую черту предшествующих записей с завершающей звездочкой: https://bugs.openjdk.java.net/browse/JDK-8131329

  • 0
    На самом деле мы сейчас используем Java 5. Но это хорошо знать на будущее, спасибо за совет!
  • 0
    Потрясающие. Как-то так у меня работает: java -cp target / classes; target / lib / * de.byteconsult.Main
Показать ещё 10 комментариев
199

В окнах это работает:

java -cp "Test.jar;lib/*" my.package.MainClass

и это не работает:

java -cp "Test.jar;lib/*.jar" my.package.MainClass

обратите внимание на *.jar, , поэтому символ * следует использовать отдельно.


В Linux следующие работы:

java -cp "Test.jar:lib/*" my.package.MainClass

Сепараторы являются двоеточиями вместо точек с запятой.

  • 15
    Идеальный ответ. 2 важные вещи, на которые следует обратить внимание: 1) Используйте кавычки и 2) Используйте только *, а не * .jar
  • 3
    Третий пример работал на Linux (Ubuntu 12.04 LTS).
Показать ещё 4 комментария
59

Мы обойдем эту проблему, развернув файл основного myapp.jar основного, который содержит файл manifest (Manifest.mf), определяющий путь к классам с другими необходимыми банками, которые затем развертываются рядом с ним. В этом случае вам нужно объявить java -jar myapp.jar при запуске кода.

Итак, если вы разворачиваете основной jar в какой-то каталог, а затем помещаете зависимые банки в папку lib ниже, манифест выглядит так:

Manifest-Version: 1.0
Implementation-Title: myapp
Implementation-Version: 1.0.1
Class-Path: lib/dep1.jar lib/dep2.jar

NB: это не зависит от платформы. Мы можем использовать те же банки для запуска на сервере UNIX или на ПК с ОС Windows.

  • 0
    Похоже, что это работает для многих людей, однако Java явно игнорирует записи Class-Path в файле манифеста. Мы не можем запустить приложение, не добавив вручную lib / * в путь к классам, используя -cp. Есть идеи?
  • 6
    ответ oxbow_lakes не совсем правильный; вещь Class-Path считается достойной (и ТОЛЬКО это учитывается; -cp / -classpath игнорируется!), если вы запускаете этот jar с помощью java -jar myapp.jar. Я предполагаю, что oxbow_lakes хотел написать это, когда он написал «java -classpath myapp.jar».
35

Мое решение на Ubuntu 10.04 с использованием java-sun 1.6.0_24 со всеми банками в каталоге "lib":

java -cp .:lib/* my.main.Class

Если это не удается, следующая команда должна работать (выводит все *.jars в каталог lib на параметр classpath)

java -cp $(for i in lib/*.jar ; do echo -n $i: ; done). my.main.Class
  • 4
    забавная записка. java -cp lib / * my.main.Class всегда будет терпеть неудачу, потому что расширение glob оболочки lib / *, в то время как java -cp.: lib / * my.main.Class не будет, потому что.: lib / * не является допустимым glob дорожка. Найдите время, чтобы отметить, что
  • 1
    Это не работает; Linux расширит . Вы можете попробовать: java -cp '.: lib / ', и это прекрасно работает (обратите внимание на одинарные кавычки! Это не будет работать с двойными кавычками!). На самом деле,.: Lib / * может сработать, если это недопустимый глобус из-за двоеточия, но это кажется немного ненадежным. Я бы добавил цитаты. Одиночные кавычки говорят bash не касаться какой-либо части содержимого.
Показать ещё 2 комментария
28

Короткий ответ: java -classpath lib/*:. my.package.Program

Oracle предоставляет документацию по использованию подстановочных знаков в classpaths здесь для Java 6 и здесь для Java 7, под заголовком раздела Общие сведения о шаблонах пути к классам. (Поскольку я пишу это, две страницы содержат ту же информацию.) Здесь краткое изложение основных моментов:

  • В общем, чтобы включить все JAR в данный каталог, вы можете использовать подстановочный знак * ( не *.jar).

  • Подстановочный знак соответствует только JAR, а не файлам классов; чтобы получить все классы в каталоге, просто закончите запись пути к классу в имени каталога.

  • Вышеуказанные два параметра можно объединить, чтобы включить все JAR и файлы классов в каталог, и применяются обычные правила приоритета classpath. Например. -cp /classes;/jars/*

  • Подкаталог будет не искать JAR в подкаталогах.

  • Вышеуказанные маркерные точки верны, если вы используете системное свойство CLASSPATH или флаги командной строки -cp или -classpath. Однако, если вы используете заголовок манифеста Class-Path JAR (как вы можете сделать с файлом сборки ant), подстановочные знаки будут не выполняться.

Да, моя первая ссылка такая же, как и в ответе на лучший результат (который я не надеюсь на обгон), но этот ответ не дает много объяснений за пределами ссылки. Поскольку такое поведение обескуражено в Qaru в эти дни, я подумал, что я расширю его.

  • 0
    моя проблема была с lib / *. jar, а не с lib / *. Большое спасибо это исправило. Я заметил, что есть разница между: и; но это могло бы быть моим испытанием - много изменений в то же самое время.
  • 0
    Спасибо за то, что подчеркнули разницу между * и * .jar
26

Для меня это работает в окнах.

java -cp "/lib/*;" sample

Для linux

java -cp "/lib/*:" sample

Я использую Java 6

  • 0
    ты спас мой день
  • 0
    Пример Windows, кажется, работал для Java 6, может быть Java 7, но не для Java 8 (см. bugs.openjdk.java.net/browse/JDK-8131329 )
Показать ещё 1 комментарий
22

Вы можете попробовать java -Djava.ext.dirs=jarDirectory http://docs.oracle.com/javase/6/docs/technotes/guides/extensions/spec.html

Каталог внешних банок при запуске java

  • 3
    Это работает, но -Djava.ext.dirs= , передайте -Djava.ext.dirs= BEFORE -jar
  • 4
    java.ext.dirs будет работать совсем не так, как обычный jar в classpath. У него более высокий приоритет и разрешение, которое может каким-то образом переопределять классы в начальной загрузке (rt.jar).
Показать ещё 1 комментарий
20

Правильно

java -classpath "lib/*:." my.package.Program

Неправильно:

java -classpath "lib/a*.jar:." my.package.Program
java -classpath "lib/a*:."     my.package.Program
java -classpath "lib/*.jar:."  my.package.Program
java -classpath  lib/*:.       my.package.Program
13

Окно:
 java -cp file.jar; dir/* my.app.ClassName

Linux:
java -cp file.jar: dir/* my.app.ClassName

Напомните:
- разделитель путей Windows - ; "
- Linux разделитель путей : "
- В Windows, если аргумент cp не содержит пробел, "кавычки" являются необязательными

  • 0
    Пример Windows не работает для Java 8 и более ранних версий : см. bugs.openjdk.java.net/browse/JDK-8131329
  • 0
    Может быть, не работает для открытого JDK, я буду проверять это, и я буду говорить здесь
Показать ещё 2 комментария
8

Если вы используете Java 6, вы можете использовать подстановочные знаки в пути к классам.

Теперь можно использовать подстановочные знаки в определении пути к классам:

javac -cp libs/* -verbose -encoding UTF-8 src/mypackage/*.java  -d build/classes

Ссылка: http://www.rekk.de/bloggy/2008/add-all-jars-in-a-directory-to-classpath-with-java-se-6-using-wildcards/

8

Если вам действительно нужно указать все .jar файлы динамически, вы можете использовать сценарии оболочки, или Apache Ant. Там есть проект commons Commons Launcher, который в основном позволяет указать ваш запуск script как файл сборки ant (если вы понимаете, что я имею в виду).

Затем вы можете указать что-то вроде:

<path id="base.class.path">
    <pathelement path="${resources.dir}"/>
    <fileset dir="${extensions.dir}" includes="*.jar" />
    <fileset dir="${lib.dir}" includes="*.jar"/>
</path>

В вашем файле сборки запуска, который запустит ваше приложение с правильным пути к классам.

7

Обратите внимание, что расширение подстановочного символа нарушено для Java 7 в Windows.

Подробнее о https://stackoverflow.com/questions/9195073/broken-wildcard-expansion-for-java7-commandline-on-windows7.

Обходной путь заключается в том, чтобы поставить точку с запятой сразу после шаблона. java -cp "somewhere/*;"

5

К кому это может относиться,

Я нашел это странное поведение в Windows под оболочкой MSYS/MinGW.

Работает:

$ javac -cp '.;c:\Programs\COMSOL44\plugins\*' Reclaim.java

Не работает:

$ javac -cp 'c:\Programs\COMSOL44\plugins\*' Reclaim.java
javac: invalid flag: c:\Programs\COMSOL44\plugins\com.comsol.aco_1.0.0.jar
Usage: javac <options> <source files>
use -help for a list of possible options

Я совершенно уверен, что подстановочный знак не расширяется оболочкой, потому что, например,

$ echo './*'
./*

(Пробовал и другую программу, а не встроенную echo, с тем же результатом.)

Я считаю, что он javac, который пытается его расширить, и ведет себя по-разному, есть ли точка с запятой в аргументе или нет. Во-первых, он может пытаться расширить все аргументы, которые выглядят как пути. И только тогда он будет разбирать их, -cp принимает только следующий токен. (Обратите внимание, что com.comsol.aco_1.0.0.jar является вторым JAR в этом каталоге.) Это все предположение.

Это

$ javac -version
javac 1.7.0
3

Короткая форма: если ваша основная часть находится в банке, вам, вероятно, понадобится дополнительный "-jar pathTo/yourJar/YourJarsName.jar", явно объявленный для ее работы (даже если "YourJarsName.jar" был в пути к классам ) (или, выраженный, чтобы ответить на исходный вопрос, который был задан 5 лет назад: вам не нужно явно обновлять каждую банку, но, похоже, даже с java6 вам нужно обновить свою собственную банку...)


Длинная форма: (Я сделал это явным до такой степени, что, надеюсь, даже нарушители java могут использовать это)

Как и многие другие, я использую eclipse для экспорта jars: (File- > Export → 'Runnable JAR File'). В разделе "Обработка библиотеки" eclipse (Juno) есть три варианта:

opt1: "Extract required libraries into generated JAR"
opt2: "Package required libraries into generated JAR"
opt3: "Copy required libraries into a sub-folder next to the generated JAR"

Как правило, я бы использовал opt2 (и opt1 был определенно разбит), однако собственный код в одной из банок, которые я использую, я обнаружил перерывы с удобным трюком "jarinjar", который затмевает, когда вы выберете этот параметр. Даже после того, как я понял, мне нужен opt3, а затем, найдя эту запись StackOverflow, мне все же понадобилось некоторое время, чтобы понять, как запустить мою основную внешность затмения, поэтому вот что сработало для меня, поскольку оно полезно для других...


Если вы назвали свою банку: "fooBarTheJarFile.jar" и все установлено для экспорта в каталог: "/theFully/qualifiedPath/toYourChosenDir".

(это означает, что поле "Место для экспорта" будет читать: '/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar')

После того, как вы нажмете на конец, вы увидите, что eclipse помещает все библиотеки в папку с именем 'fooBarTheJarFile_lib' в этом каталоге экспорта, что дает вам что-то вроде:

/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar01.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar02.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar03.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar04.jar

Затем вы можете запускать из любой точки вашей системы с помощью:

java -classpath "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/*" -jar  /theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar   package.path_to.the_class_with.your_main.TheClassWithYourMain

(для Java Newbies: 'package.path_to.the_class_with.your_main' - объявленный пакетный путь, который вы найдете в верхней части файла TheClassWithYourMain.java, который содержит "main (String [] args) {...} ', который вы хотите запустить извне java)


Ловушка, чтобы заметить: это наличие "fooBarTheJarFile.jar" в списке банок на объявленном пути к классам недостаточно. Вам нужно явно объявить "-jar" и обновить местоположение этой банки.

например. это нарушает:

 java -classpath "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar;/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/*"  somepackages.inside.yourJar.leadingToTheMain.TheClassWithYourMain

пересчитывается относительными путями:

cd /theFully/qualifiedPath/toYourChosenDir/;
BREAKS:  java -cp "fooBarTheJarFile_lib/*"                                package.path_to.the_class_with.your_main.TheClassWithYourMain    
BREAKS:  java -cp ".;fooBarTheJarFile_lib/*"                              package.path_to.the_class_with.your_main.TheClassWithYourMain   
BREAKS:  java -cp ".;fooBarTheJarFile_lib/*"   -jar                       package.path_to.the_class_with.your_main.TheClassWithYourMain   
WORKS:   java -cp ".;fooBarTheJarFile_lib/*"   -jar  fooBarTheJarFile.jar package.path_to.the_class_with.your_main.TheClassWithYourMain   

(с использованием java-версии "1.6.0_27", с помощью 64-разрядной виртуальной машины OpenJDK на ubuntu 12.04)

3

Все вышеперечисленные решения отлично работают, если вы разрабатываете и запускаете приложение Java вне любой среды IDE, например Eclipse или Netbeans.

Если вы используете Windows 7 и используете Eclipse IDE для разработки на Java, вы можете столкнуться с проблемами при использовании командной строки для запуска файлов классов, встроенных в Eclipse.

например. Исходный код в Eclipse имеет следующую иерархию пакетов: edu.sjsu.myapp.Main.java

У вас есть json.jar как внешняя зависимость для Main.java

При попытке запустить Main.java из Eclipse он будет работать без каких-либо проблем.

Но когда вы пытаетесь запустить это с помощью командной строки после компиляции Main.java в Eclipse, он будет снимать некоторые странные ошибки, говорящие "ClassNotDef Error blah blah".

Я предполагаю, что вы находитесь в рабочем каталоге исходного кода.

Используйте следующий синтаксис для запуска из командной строки:

  • javac -cp "; json.jar" Main.java

  • java -cp "; json.jar" edu.sjsu.myapp.Main

    [Не пропустите. выше]

Это связано с тем, что вы разместили Main.java внутри пакета edu.sjsu.myapp и java.exe будет искать точный шаблон.

Надеюсь, что это поможет!

3

Для окон требуются кавычки и; следует использовать в качестве разделителя. например:.

java -cp "target\\*;target\\dependency\\*" my.package.Main
2

класс из wepapp:

  > mvn clean install

  > java -cp "webapp/target/webapp-1.17.0-SNAPSHOT/WEB-INF/lib/tool-jar-1.17.0-SNAPSHOT.jar;webapp/target/webapp-1.17.0-SNAPSHOT/WEB-INF/lib/*" com.xx.xx.util.EncryptorUtils param1 param2
2

Единственный способ, которым я знаю, как это сделать индивидуально, например:

setenv CLASSPATH /User/username/newfolder/jarfile.jar:jarfile2.jar:jarfile3.jar:.

Надеюсь, что это поможет!

  • 0
    Возможно, это был единственный путь назад в 2008 году, но не больше.
  • 0
    Это не самое страшное. Это хак, но у меня есть этот набор в моем bashrc for jar in $(ls $HOME/bin/*.jar); do export CLASSPATH=$jar:$CLASSPATH; done
1

Дикие карты были введены из Java 6. В записи пути класса может содержаться символ подстановочного имени базы данных *, который считается эквивалентным заданию списка всех файлов в каталоге с расширением .jar или .JAR.

java -cp "lib/*" -jar %MAINJAR%

Если вам нужны только конкретные банки, вам нужно будет добавить их отдельно. Строка classpath не принимает общие подстановочные знаки, такие как Jar *,.jar, hiber и т.д.

Пример

Следующая запись не работает:

java -cp "Halo.jar;lib/*.jar" ni.package.MainClass

Правильная запись:

java -cp "Halo.jar;lib/*" ni.package.MainClass

Подробнее о.... Java Classpath

Rj

1

Неправильное решение для установки /* на -cp, но я надеюсь, что вы можете использовать следующий script, чтобы немного облегчить ситуацию для динамических классов классов и каталогов lib.

 libDir2Scan4jars="../test";cp=""; for j in `ls ${libDir2Scan4jars}/*.jar`; do if [ "$j" != "" ]; then cp=$cp:$j; fi; done; echo $cp| cut -c2-${#cp} > .tmpCP.tmp; export tmpCLASSPATH=`cat .tmpCP.tmp`; if [ "$tmpCLASSPATH" != "" ]; then echo .; echo "classpath set, you can now use  ~>         java -cp \$tmpCLASSPATH"; echo .; else echo .; echo "Error please check libDir2Scan4jars path"; echo .; fi; 

Сценарий для Linux может иметь аналогичный для Windows. Если в качестве входных данных в "libDir2Scan4jars" указан правильный каталог; script проверит все банки и создаст строку класса path и экспортирует ее в переменную env "tmpCLASSPATH".

0

Установите путь к классу таким образом, чтобы он соответствовал нескольким банкам и текущим файлам классов каталога.

CLASSPATH=${ORACLE_HOME}/jdbc/lib/ojdbc6.jar:${ORACLE_HOME}/jdbc/lib/ojdbc14.jar:${ORACLE_HOME}/jdbc/lib/nls_charset12.jar; 
CLASSPATH=$CLASSPATH:/export/home/gs806e/tops/jconn2.jar:.;
export CLASSPATH
0

Подумайте о файле jar в качестве корня структуры каталогов. Да, вам нужно добавить их все отдельно.

0

Вам нужно добавить их все отдельно. Кроме того, если вам действительно нужно просто указать каталог, вы можете развязать все в один каталог и добавить его в свой путь к классам. Однако я не рекомендую этот подход, так как вы рискуете причудливыми проблемами в управлении версиями classpath и неуправляемости.

  • 3
    Возможно, это был единственный путь назад в 2008 году, но не больше.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню